Tại sao điều này tìm kiếm trên BIGINT col có thêm quét liên tục, tính toán vô hướng và toán tử vòng lặp lồng nhau?


8

Khi tôi nhìn vào kế hoạch thực tế của một số truy vấn của tôi, tôi nhận thấy rằng các hằng số được sử dụng trong mệnh đề WHERE hiển thị dưới dạng một chuỗi tính toán vô hướng lồng nhau và quét liên tục .

ảnh chụp màn hình phòng thu sql

Để tái tạo điều này, tôi sử dụng bảng sau

CREATE TABLE Table1 (
    [col1] [bigint] NOT NULL,
    [col2] [varchar](50) NULL,
    [col3] [char](200) NULL
)
CREATE NONCLUSTERED INDEX IX_Table1 ON Table1 (col1 ASC)

Với một số dữ liệu trong đó:

INSERT INTO Table1(col1) VALUES (1),(2),(3),
                               (-9223372036854775808),
                               (9223372036854775807),
                               (2147483647),(-2147483648)

Khi tôi chạy truy vấn (vô nghĩa) sau:

SELECT a.col1, a.col2
  FROM Table1 a, Table1 b
  WHERE b.col1 > 2147483648

Tôi thấy rằng nó sẽ thực hiện một bản vẽ Nested Loop trong kết quả của Index Seek và phép tính vô hướng (từ một hằng số).

Lưu ý rằng nghĩa đen lớn hơn maxint. Nó giúp để viết CAST(2147483648 as BIGINT). Bất cứ ý tưởng nào tại sao MSSQL lại làm chệch hướng kế hoạch thực hiện đó và có cách nào ngắn hơn để tránh nó hơn là sử dụng diễn viên không? Nó có ảnh hưởng đến các tham số bị ràng buộc với các câu lệnh được chuẩn bị (từ JDBC của jtds không) không?

Việc tính toán vô hướng không phải lúc nào cũng được thực hiện (dường như là chỉ số tìm kiếm cụ thể). Và đôi khi bộ phân tích truy vấn không hiển thị bằng đồ họa mà như col1 < scalar(expr1000)trong các thuộc tính vị ngữ.

Tôi đã thấy điều này với MS SSMS 2016 (13.0.16100.1) và SQL Server 2014 Expres Edition 64bit trên Windows 7, nhưng tôi đoán đó là một hành vi chung.

Câu trả lời:


8
SELECT thing, 
       sql_variant_property(thing,'basetype') AS basetype,
       sql_variant_property(thing,'precision') AS precision, 
       sql_variant_property(thing,'scale') AS scale
FROM (VALUES (2147483648)) V(thing)

Cho bạn thấy rằng nghĩa đen 2147483648được hiểu là numeric(10,0). Hành vi này có trước ngày giới thiệu của bigintSQL Server (2000).

Không có cú pháp nào để chỉ ra rằng một nghĩa đen nên được coi là bigint- thêm một từ rõ ràng CASTlà giải pháp tốt nhất. Bài viết Tìm kiếm năng động và chuyển đổi ẩn ẩn thảo luận về phần còn lại của bộ máy trong kế hoạch.

Bản thân kế hoạch cho thấy các vòng lặp lồng nhau có một vị từ tìm kiếm trên

Seek Keys[1]: Start: [tempdb].[dbo].[Table1].col1 > Scalar Operator([Expr1005]), 
                End: [tempdb].[dbo].[Table1].col1 < Scalar Operator([Expr1006])

Bạn có thể sử dụng một phiên sự kiện mở rộng query_trace_column_valuesđể thấy rằng đây là những sự kiện như sau.

nhập mô tả hình ảnh ở đây

XML trong kế hoạch cũng cho thấy điều này

  <DefinedValue>
    <ValueVector>
      <ColumnReference Column="Expr1005" />
      <ColumnReference Column="Expr1006" />
      <ColumnReference Column="Expr1004" />
    </ValueVector>
    <ScalarOperator ScalarString="GetRangeWithMismatchedTypes((2147483648.),NULL,(6))">
      <Intrinsic FunctionName="GetRangeWithMismatchedTypes">
        <ScalarOperator>
          <Const ConstValue="(2147483648.)" />
        </ScalarOperator>
        <ScalarOperator>
          <Const ConstValue="NULL" />
        </ScalarOperator>
        <ScalarOperator>
          <Const ConstValue="(6)" />
        </ScalarOperator>
      </Intrinsic>
    </ScalarOperator>
  </DefinedValue>

Điều này không có nghĩa là nó là nghĩa đen làm một so sánh < nullkhá

Các biểu thức ranh giới phạm vi sử dụng NULL để biểu thị 'không giới hạn' ở hai đầu. ( Nguồn )

Vì vậy, hiệu ứng ròng là vị từ truy vấn của bạn b.col1 > CAST(2147483648 AS NUMERIC(10, 0))vẫn kết thúc bằng một tìm kiếm chống lạib.col1 > CAST(2147483648 AS BIGINT)

Nó có ảnh hưởng đến các tham số bị ràng buộc với các câu lệnh được chuẩn bị (từ JDBC của jtds không) không?

Tôi chưa sử dụng JDBC của jtds nhưng tôi cho rằng nó cho phép bạn xác định kiểu dữ liệu tham số? Nếu vậy, chỉ cần đảm bảo các tham số là kiểu dữ liệu chính xác khớp với cột ( bigint) để SQL Server không cần phải xử lý các kiểu dữ liệu không khớp.


3

Liên quan đến câu hỏi của tôi về các tuyên bố chuẩn bị JDBC. jTDS sử dụng sp_prepare/ sp_execute(ở prepareSQL=3chế độ mặc định ).

Với truy vấn sau ( nguồn ):

use database
select
    cp.objtype, st.text
from sys.dm_exec_cached_plans cp
cross apply sys.dm_exec_sql_text(cp.plan_handle) st
where cp.objtype = 'prepared' and st.text like '%TABLE%'

Tôi có thể thấy câu lệnh được chuẩn bị do JTDS ban hành và nó khai báo biến (@P0 bigint)...như mong đợi.

Vì vậy, điều này là tốt và tôi cần nhớ rằng khi thử các kế hoạch thực hiện, tốt hơn là nên xác định các biến được gõ cục bộ thay vì thay thế chúng bằng chữ (và / hoặc sử dụng sp_executeđể nhấn vào kế hoạch thực hiện được lưu trong bộ nhớ cache).


1
Ngoài ra, bạn có thể biến nó thành một quy tắc với bạn luôn để chuyển nghĩa đen của bạn sang loại cột bạn phù hợp với.
Andriy M
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.