Truy vấn chậm khi có 'chứa' và '=' trong mệnh đề where


8

Truy vấn sau mất khoảng 10 giây để hoàn thành trên một bảng có 12k hồ sơ

select top (5) *
from "Physician"
where "id" = 1 or contains("lastName", '"a*"')

Nhưng nếu tôi thay đổi mệnh đề where thành một trong hai

where "id" = 1

hoặc là

where contains("lastName", '"a*"')

Nó sẽ trở lại ngay lập tức.

Cả hai cột đều được lập chỉ mục và cột lastName cũng được lập chỉ mục toàn văn.

CREATE TABLE Physician
(
   id         int identity    NOT NULL,
   firstName  nvarchar(100)   NOT NULL,
   lastName   nvarchar(100)   NOT NULL
);

ALTER TABLE Physician
  ADD CONSTRAINT Physician_PK
  PRIMARY KEY CLUSTERED (id);

CREATE NONCLUSTERED INDEX Physician_IX2
   ON Physician (firstName ASC);

CREATE NONCLUSTERED INDEX Physician_IX3
   ON Physician (lastName ASC);

CREATE FULLTEXT INDEX
    ON "Physician" ("firstName" LANGUAGE 0x0, "lastName" LANGUAGE 0x0)
    KEY INDEX "Physician_PK"
    ON "the_catalog"
    WITH stoplist = off;

Đây là kế hoạch thực hiện

Điều gì có thể là vấn đề?


Tôi vừa thêm định nghĩa bảng
Hooman Valibeigi

Câu trả lời:


11

Kế hoạch thực hiện của bạn

Khi nhìn vào kế hoạch truy vấn, chúng ta có thể thấy rằng một chỉ mục được chạm để phục vụ hai hoạt động của bộ lọc.

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

Rất đơn giản, do toán tử TOP, một mục tiêu hàng đã được đặt. Nhiều thông tin và điều kiện tiên quyết về các mục tiêu hàng có thể được tìm thấy ở đây

Từ cùng một nguồn:

Chiến lược mục tiêu hàng nói chung có nghĩa là ưu tiên các hoạt động điều hướng không chặn (ví dụ: các vòng lặp lồng nhau tham gia, tìm kiếm chỉ mục và tra cứu) trong việc chặn, các hoạt động dựa trên tập hợp như sắp xếp và băm. Điều này có thể hữu ích bất cứ khi nào khách hàng có thể hưởng lợi từ việc khởi động nhanh và dòng hàng ổn định (có lẽ thời gian thực hiện tổng thể dài hơn - xem bài đăng của Rob Farley ở trên). Ngoài ra còn có cách sử dụng rõ ràng và truyền thống hơn, ví dụ như trong việc trình bày kết quả một trang tại một thời điểm.

Toàn bộ bảng được thăm dò vào các bộ lọc với việc sử dụng liên kết bán bên trái có mục tiêu hàng được đặt, hy vọng sẽ trả về 5 hàng nhanh nhất và hiệu quả nhất có thể.

Điều này không xảy ra, dẫn đến nhiều lần lặp lại trên TVF .ulltextmatch.

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


Tái tạo

Dựa trên kế hoạch của bạn , tôi đã có thể tái tạo phần nào vấn đề của bạn:

CREATE TABLE dbo.Person(id int not null,lastname varchar(max));

CREATE UNIQUE INDEX ui_id ON  dbo.Person(id)
CREATE FULLTEXT CATALOG ft AS DEFAULT;  
CREATE FULLTEXT INDEX ON dbo.Person(lastname)   
   KEY INDEX ui_id   
   WITH STOPLIST = SYSTEM;  
GO  

INSERT INTO dbo.Person(id,lastname)
SELECT top(12000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)),
REPLICATE(CAST('A' as nvarchar(max)),80000)+ CAST(ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as varchar(10))
FROM master..spt_values spt1
CROSS APPLY master..spt_values spt2;
CREATE CLUSTERED INDEX cx_Id on dbo.Person(id);

Chạy truy vấn

SELECT TOP (5) *
FROM dbo.Person
WHERE "id" = 1 OR contains("lastName", '"B*"');

Kết quả thành một kế hoạch truy vấn có thể so sánh với bạn:

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

Trong ví dụ trên, B không tồn tại trong chỉ mục fulltext. Kết quả là nó phụ thuộc vào tham số & dữ liệu hiệu quả của kế hoạch truy vấn.

Một lời giải thích tốt hơn về điều này có thể được tìm thấy trong Row Goals, Phần 2: Semi Joins của Paul White

... Nói cách khác, trên mỗi lần lặp lại của một ứng dụng, chúng ta có thể ngừng nhìn vào đầu vào B ngay khi tìm thấy kết quả khớp đầu tiên, sử dụng biến vị ngữ nối xuống. Đây chính xác là loại điều mà mục tiêu hàng phù hợp để: tạo ra một phần của kế hoạch được tối ưu hóa để nhanh chóng trả lại n hàng đầu tiên (trong đó n = 1 ở đây).

Ví dụ: thay đổi vị ngữ để kết quả được tìm thấy sớm hơn (khi bắt đầu quét).

select top (5) *
from dbo.Person
where "id" = 124 
or contains("lastName", '"A*"');

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

các where "id" = 124bị loại bỏ do vị chỉ số toàn văn đã trở về 5 hàng, đáp ứng được các TOP()vị ngữ.

Kết quả cũng cho thấy điều này

id lastname 
1  'AAA...'   
2  'AAA...'
3  'AAA...'
4  'AAA...'
5  'AAA...'

Và TVF thực thi:

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

Chèn một số hàng mới

INSERT INTO dbo.Person
SELECT 12001, REPLICATE(CAST('B' as nvarchar(max)),80000);
INSERT INTO dbo.Person
SELECT 12002, REPLICATE(CAST('B' as nvarchar(max)),80000);

Chạy truy vấn để tìm các hàng được chèn trước đó

SELECT TOP (2) *
from dbo.Person
where "id" = 1
or contains("lastName", '"B*"');

Điều này một lần nữa dẫn đến quá nhiều lần lặp lại trên hầu hết tất cả các hàng để trả về giá trị cuối cùng nhưng một giá trị được tìm thấy.

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

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

id   lastname
1     'AAA...'
12001 'BBB...'

Giải quyết

Khi xóa mục tiêu hàng bằng cách sử dụng trackflag 4138

SELECT TOP (5) *
FROM dbo.Person
WHERE "id" = 124 
OR contains("lastName", '"B*"')
OPTION(QUERYTRACEON 4138 );

Trình tối ưu hóa sử dụng mô hình nối gần hơn để thực hiện a UNION, trong trường hợp của chúng tôi, điều này là thuận lợi vì nó đẩy các biến vị ngữ xuống chỉ số cụm được tìm kiếm tương ứng của chúng và không sử dụng toán tử nửa liên kết được nhắm mục tiêu.

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

Một cách khác để viết điều này, mà không sử dụng dấu vết được đề cập ở trên:

SELECT top (5) *
FROM
(
SELECT * 
FROM dbo.Person
WHERE "id" = 1 
UNION
SELECT * 
FROM dbo.Person
WHERE contains("lastName", '"B*"')
 ) as A;

Với kế hoạch truy vấn kết quả:

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

nơi chức năng fulltext được áp dụng trực tiếp

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

Là một sidenote, đối với op, trình tối ưu hóa truy vấn hotfix trackflag 4199 đã giải quyết vấn đề của anh ta. Ông đã thực hiện điều này bằng cách thêm OPTION(QUERYTRACEON(4199))vào truy vấn. Tôi đã không thể tái tạo hành vi đó vào cuối của tôi. Hotfix này có chứa tối ưu hóa bán tham gia:

Cờ theo dõi: 4102 Chức năng: SQL 9 - Hiệu suất truy vấn chậm nếu kế hoạch thực hiện truy vấn có chứa toán tử bán tham gia Thông thường, toán tử bán tham gia được tạo khi truy vấn chứa từ khóa IN hoặc từ khóa EXISTS. Cho phép cờ 4102 và 4118 để khắc phục điều này.

Nguồn


Thêm

Trong quá trình tối ưu hóa dựa trên chi phí, trình tối ưu hóa cũng có thể thêm một bộ đệm chỉ mục vào kế hoạch thực hiện, được thực hiện bởi LogOp_Spool Index on fly Eager (hoặc đối tác vật lý)

Nó thực hiện điều này với tập dữ liệu của tôi cho TOP(3)nhưng không phải choTOP(2)

SELECT TOP (3) *
from dbo.Physician
where "id" = 1
or contains("lastName", '"B*"')  

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

Trong lần thực hiện đầu tiên, một bộ đệm háo hức đọc và lưu trữ toàn bộ đầu vào trước khi trả về tập hợp con của các hàng được yêu cầu bởi các thực thi Dự đoán sau đó đọc và trả về cùng một hoặc một tập hợp con khác của các hàng từ bàn làm việc, mà không bao giờ phải thực thi con nút một lần nữa.

Nguồn

Với vị từ tìm kiếm được áp dụng cho chỉ số háo hức này:

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


Bạn có thể giải thích việc sử dụng Cờ Trace không? Có một chút không rõ ràng từ mã của bạn những gì họ đang làm
George.Palacios

1
@ George.Palacios Vâng, tôi đã tạo ra một chút hỗn độn của tất cả: ^). Sẽ làm cảm ơn cho các thông tin phản hồi!
Randi Vertongen

Không phải các cờ QUERYTRACEON được đề xuất của bạn (4138, 3604, 8607, 8612) đã hoạt động, nhưng QUERYTRACEON 4199 xảy ra để khắc phục sự cố !!!!
Hooman Valibeigi

Lưu ý rằng truy vấn chậm ngay cả khi không có toán tử TOP
Hooman Valibeigi

@HoomanValibeigi bạn đã thử giải pháp công đoàn ở phía dưới chưa?
Randi Vertongen
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.