Lượt truy cập hiệu suất bằng CAST trong T-SQL


12

Chúng tôi có một trình tạo SQL phát ra các câu lệnh có điều kiện SQL một cách tổng quát cho các trường được chỉ định (để thảo luận: chúng tôi sẽ gắn nhãn là myField).

Nếu myFieldlà kiểu NVARCHAR, chúng ta có thể so sánh trường đã nói với một chuỗi như vậy : myField = 'foo'.

Tuy nhiên, điều này không hoạt động cho các lĩnh vực loại NTEXT. Vì vậy, chúng tôi phải làm so sánh với một diễn viên : CAST(myField as NVARCHAR(MAX)) = 'foo'. Điều này trong thực tế sẽ làm việc nếu myFieldlà loại NVARCHARhoặc NTEXT.

Hiệu suất thành công của việc thực hiện các diễn viên đã nói ở trên trên một lĩnh vực đã thuộc loại NVARCHARnào? Hy vọng của tôi là SQL Server đủ thông minh để tự động nhận ra đó myFieldlà loại NVARCHAR(có hiệu quả biến CASTthành không hoạt động).


Lưu ý nhanh cho bất kỳ ai tìm thấy câu hỏi này: NTEXT (và TEXT và IMAGE) chính thức không được chấp nhận và do bị xóa trong một số phiên bản tương lai của SQL Server (mặc dù IIRC chúng vẫn hoạt động trong SQL1014), vì vậy bạn nên sử dụng NVARCHR (MAX) (hoặc VARCHAR (MAX) hoặc VARBINARY (MAX)) thay vào đó. Việc thay thế cột NTEXT bằng một NVARCHAR (MAX) trong trường hợp này sẽ loại bỏ sự cần thiết của diễn viên vì việc so sánh có thể được thực hiện trực tiếp với loại đó và cũng có những mức tăng hiệu quả tiềm năng khác ở đây và ở những nơi khác. Thật không may, bạn không thể lập chỉ mục cột * (MAX), nhưng bạn cũng không thể lập cột văn bản / NTEXT.
David Spillett

Câu trả lời:


12

Nếu việc chọn cột là chính xác cùng một kiểu dữ liệu và độ dài và vị từ tìm kiếm là một nghĩa đen thì nó thực sự dường như coi thường nó hoặc coi nó là một no-op và chỉ mục tìm kiếm sự bình đẳng.

Seek Keys[1]: Prefix: [tempdb].[dbo].[#test].name = Scalar Operator(N'rpc')

Nếu việc truyền của cột là cùng một kiểu dữ liệu nhưng độ dài lớn hơn và vị từ tìm kiếm là một chuỗi bằng chữ thì nó gây ra quét chỉ mục. Điều này rõ ràng là để tránh.

Nếu việc truyền của cột là cùng một kiểu dữ liệu và có cùng độ dài hoặc lớn hơn và biến vị ngữ tìm kiếm là một biến cục bộ, nó sẽ thêm một toán tử vô hướng tính toán vào kế hoạch thực hiện. Điều này gọi GetRangeThroughConvertvà đầu ra một phạm vi.

Phạm vi này được sử dụng để thực hiện tìm kiếm chỉ mục và có vẻ khá hiệu quả

Seek Keys[1]: 
Start: [tempdb].[dbo].[#test].name > Scalar Operator([Expr1006]), 
End: [tempdb].[dbo].[#test].name < Scalar Operator([Expr1007])

Mã kiểm tra

SELECT *
 INTO #test
  FROM [master].[dbo].[spt_values]

CREATE NONCLUSTERED INDEX [ixname] ON #test
(
    [name] ASC
)

DECLARE @name NVARCHAR(MAX)

SET @name = 'rpc'

SELECT name
FROM #test
WHERE CAST(name AS NVARCHAR(35))= @name --Cast the same and local variable

SELECT name
FROM #test
WHERE CAST(name AS NVARCHAR(MAX))=@name --Cast to longer and local variable

SELECT name
FROM #test
WHERE CAST(name AS NVARCHAR(35))='rpc' --Cast the same and literal

SELECT name
FROM #test
WHERE CAST(name AS NVARCHAR(MAX))='rpc' --Cast to longer and literal

6

Nói chung, CASThiệu suất sẽ giết chết vì nó vô hiệu hóa bất kỳ việc sử dụng chỉ mục nào như ví dụ cuối cùng của Martin Smith cho thấy. Truyền tới nvarchar(max)hoặc đến một độ dài khác nhau có nghĩa là một loại dữ liệu khác: thực tế tất cả đều nvarcharkhông liên quan.

Trên hết, kiểu dữ liệu của phía bên phải của vấn đề so sánh cũng vậy. Nếu đó là một biến cục bộ hoặc tham số có độ dài khác nhau thì một bên sẽ được mặc định CASTlà rộng nhất trong 2 kiểu dữ liệu (xem ưu tiên kiểu dữ liệu ).

Về cơ bản, nếu bạn có một vị tướng CASTđể nvarchar(max)nó sẽ bollix mọi thứ lên. Tôi sẽ xem xét sửa chữa việc sử dụng ntexttrước khi tôi thêm CASTtất cả.

Việc chuyển đổi có thể không hiển thị trong kế hoạch truy vấn. Xem bài viết trên blog của Paul White


2

Chỉ cần một lưu ý, Đúc như thế này trong đó Datecreated là datetime

 Cast (Datecreated as date) = cast(@MydatetimeValue as date)

Không phá vỡ khả năng sử dụng các chỉ mục của SQL nếu các chỉ mục tồn tại và nếu chúng không tồn tại, có thể dẫn đến việc ghi lại một chỉ mục bị thiếu.

Tương tự, khi truyền từ intđến tinyinthoặc bigintsang intvv, hàm cast không ngăn SQL sử dụng các chỉ mục NẾU trình tối ưu hóa biết rằng hoạt động truyền không thay đổi thứ tự sắp xếp của 2 kiểu dữ liệu so sánh.

Dưới đây là một loạt các thử nghiệm bạn có thể chạy và xem kế hoạch thực tế bằng Adventureworks2008R2

select count(*) from Sales.SalesOrderDetail where SalesOrderID = 8 --1
select top 10 * from Sales.SalesOrderDetail where cast(SalesOrderID as tinyint) = 8  --2
select top 10 * from Sales.SalesOrderDetail where cast(SalesOrderID as bigint) = 8  --3
select top 10 SalesOrderID from Sales.SalesOrderDetail where cast(ModifiedDate  as date) = '19780322' --4
select top 10 SalesOrderID from Sales.SalesOrderDetail where convert(date,ModifiedDate) = '19780322'  --5
select top 10 SalesOrderID from Sales.SalesOrderDetail where cast(ModifiedDate as varchar(20)) = '1978'  --6 -- THIS WILL NOT USE INDEX
select  SalesOrderID from Sales.SalesOrderDetail where cast(ModifiedDate  as date) between '19780101' and '19780109'  --7

1
diễn viên như ngày có thể thực hiện tìm kiếm chỉ mục nhưng vẫn có vấn đề so với biểu hiện dưới dạng tìm kiếm phạm vi mà không có diễn viên.
Martin Smith
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.