Trường được tính toán SQL trong cả mệnh đề SELECT và GROUP BY


11

Thông thường khi truy vấn cơ sở dữ liệu MS SQL Server của tôi, tôi cần tạo một trường được tính toán, chẳng hạn như

(CASE WHEN A.type = 'Workover' THEN 'Workover' 
      ELSE (CASE WHEN substring(C.category, 2, 1) = 'D' THEN 'Drilling' 
                 WHEN substring(C.category, 2, 1) = 'C' THEN 'Completion' 
                 WHEN substring(C.category, 2, 1) = 'W' THEN 'Workover' 
                 ELSE 'Other' 
            END)
END)

và sau đó tôi cần nhóm các kết quả của mình theo trường được tính toán này (trong số các trường khác). Do đó, tôi có cùng một phép tính trong cả hai mệnh đề CHỌN và NHÓM THEO. Là máy chủ SQL thực sự thực hiện các tính toán này hai lần, hay nó đủ thông minh để chỉ thực hiện một lần?

Câu trả lời:


13

Tôi có cùng một phép tính trong cả hai mệnh đề CHỌN và NHÓM THEO. Là máy chủ SQL thực sự thực hiện các tính toán này hai lần, hay nó đủ thông minh để chỉ thực hiện một lần?

Câu trả lời đơn giản là SQL Server không đảm bảo chung về thời điểm và bao nhiêu lần, một biểu thức vô hướng sẽ được đánh giá tại thời điểm thực hiện.

Có tất cả các loại hành vi phức tạp (và không có giấy tờ) trong trình tối ưu hóa và công cụ thực thi liên quan đến vị trí, thực thi và lưu trữ các biểu thức vô hướng. Sách trực tuyến không có nhiều điều để nói về điều này, nhưng những gì nó nói là thế này:

Tính toán mô tả vô hướng

Điều này mô tả một trong những hành vi mà tôi đã đề cập trước đó, trì hoãn việc thực hiện các biểu thức. Tôi đã viết về một số hành vi hiện tại khác (có thể thay đổi bất cứ lúc nào) trong bài đăng trên blog này .

Một xem xét khác là mô hình chi phí được sử dụng bởi trình tối ưu hóa truy vấn hiện không làm được gì nhiều trong cách ước tính chi phí cho các biểu thức vô hướng. Không có khung chi phí mạnh mẽ, các kết quả hiện tại được dựa trên các heuristic rộng hoặc cơ hội thuần túy.

Đối với các biểu thức rất đơn giản, có lẽ nó không tạo ra nhiều khác biệt cho dù biểu thức được đánh giá một lần hay nhiều lần trong hầu hết các trường hợp. Điều đó nói rằng, tôi đã gặp phải các truy vấn lớn trong đó hiệu năng đã bị ảnh hưởng bất lợi khi biểu thức được đánh giá một cách dư thừa một số lần rất lớn hoặc việc đánh giá xảy ra trên một luồng trong đó có thể thuận lợi để đánh giá trong một nhánh song song của thực thi kế hoạch.

Tóm lại, hành vi hiện tại không được xác định và không có gì nhiều trong các kế hoạch thực hiện để giúp bạn tìm hiểu điều gì đã xảy ra (và sẽ không thuận tiện khi đính kèm trình gỡ lỗi để kiểm tra các hành vi chi tiết của công cụ, như trong bài đăng trên blog).

Nếu bạn gặp phải trường hợp vấn đề đánh giá vô hướng có liên quan đến hiệu suất, hãy nêu vấn đề với Hỗ trợ của Microsoft. Đây là cách tốt nhất để cung cấp phản hồi để cải thiện các phiên bản tương lai của sản phẩm.


3

Như nhận xét về câu hỏi của bạn, câu trả lời là (ít nhất là theo kinh nghiệm của tôi) "có". SQL Server thường đủ thông minh để tránh tính toán lại. Bạn có thể có thể xác minh điều này bằng cách hiển thị kế hoạch thực hiện từ bên trong SQL Server Management Studio. Mỗi trường được tính được chỉ định Exprxxxxx(trong đó xxxxx là một số). Nếu bạn biết phải tìm gì, bạn sẽ có thể xác minh rằng nó sử dụng cùng một biểu thức.

Để thêm vào cuộc thảo luận, tùy chọn thẩm mỹ khác của bạn là biểu thức bảng chung :

with [cte] as
(
    select
        (case when a.type = 'workover' then 'workover' else 
        (case when substring(c.category, 2, 1) = 'd' then 'drilling'
              when substring(c.category, 2, 1) = 'c' then 'completion'
              when substring(c.category, 2, 1) = 'w' then 'workover'
              else 'other' end)
         end)) as [group_key],
         *
    from
        [some_table]
)
select
    [group_key],
    count(*) as [count]
from
    [cte]
group by
    [group_key]

Câu trả lời ngắn, chúng giống nhau về mặt chức năng với một khung nhìn, nhưng chỉ hợp lệ để sử dụng trong câu lệnh tiếp theo. Tôi thấy chúng chủ yếu là một sự thay thế dễ đọc hơn cho các bảng dẫn xuất bởi vì nó tránh lồng nhau.

Mặc dù không liên quan đến câu hỏi này, nhưng chúng có thể tự tham khảo và theo cách đó được sử dụng để xây dựng các truy vấn đệ quy.


@Quick Joe Smith: Tôi sẽ nghĩ bạn đúng về Exprxxxxx, vì tôi cũng đã thấy điều đó. Tuy nhiên, nếu tôi đặt tên cho biểu thức theo cách thủ công (trường hợp ... kết thúc) là OpType, thì hãy sử dụng trường OpType trong mệnh đề GROUP BY, tôi gặp lỗi đó là tên cột không hợp lệ.
Tiến sĩ Drew

Thật không may, đôi khi cách duy nhất của bạn trong việc chỉ định biểu thức hai lần là sử dụng một trong các phương pháp trên: CTE, dạng xem hoặc truy vấn lồng nhau.
Nhanh chóng Joe Smith

2
Trừ khi bạn cũng biết về CROSS ỨNG DỤNG .
Andriy M

Sử dụng cross applytrong trường hợp này là một chút kéo dài, và nó rất có thể sẽ gây hại cho hiệu suất bằng cách giới thiệu một sự tự tham gia không cần thiết.
Nhanh Joe Smith

2
Tôi không nghĩ bạn "có" lời đề nghị. Các CROSS APPLYchỉ định nghĩa các bí danh từ cột trong cùng một dòng. Không cần tham gia. ví dụSELECT COUNT(*), hilo FROM master..spt_values CROSS APPLY (VALUES(high + low)) V(hilo) GROUP BY hilo
Martin Smith

1

Hiệu suất chỉ là một khía cạnh. Cái khác là khả năng bảo trì.

Cá nhân, tôi có xu hướng làm như sau:

SELECT T.GroupingKey, SUM(T.value)
FROM
(
    SELECT 
        A.*
        (CASE WHEN A.type = 'Workover' THEN 'Workover' ELSE 
        (CASE WHEN substring(C.category, 2, 1) = 'D' THEN 'Drilling' WHEN substring(C.category, 2, 1) = 'C' THEN 'Completion' WHEN substring(C.category, 2, 1) = 'W' THEN 'Workover' ELSE 'Other' END)
        END) AS GroupingKey
    FROM Table AS A
) AS T

GROUP BY T.GroupingKey

CẬP NHẬT:

Nếu bạn không thích làm tổ, bạn có thể tạo XEM cho mỗi bảng nơi bạn cần sử dụng các biểu thức phức tạp.

CREATE VIEW TableExtended
AS 
SELECT 
    A.*
    (CASE WHEN A.type = 'Workover' THEN 'Workover' ELSE 
    (CASE WHEN substring(C.category, 2, 1) = 'D' THEN 'Drilling' WHEN substring(C.category, 2, 1) = 'C' THEN 'Completion' WHEN substring(C.category, 2, 1) = 'W' THEN 'Workover' ELSE 'Other' END)
    END) AS GroupingKey
FROM Table AS A

Sau đó, bạn có thể chọn mà không cần làm thêm;

SELECT GroupingKey, SUM(value)
FROM TableExtended
GROUP BY GroupingKey
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.