Chỉ mục tìm kiếm chậm hơn nhiều với điều kiện OR so với các CHỌN riêng


8

Dựa trên những câu hỏi và câu trả lời được đưa ra:

Máy chủ SQL 2008 - mất hiệu năng có thể được kết nối với một bảng rất lớn

Bảng lớn với dữ liệu lịch sử phân bổ quá nhiều SQL Server 2008 Std. bộ nhớ - mất hiệu năng cho các cơ sở dữ liệu khác

Tôi có một bảng trong cơ sở dữ liệu SupervisionP được định nghĩa như thế này:

CREATE TABLE [dbo].[PenData](
    [IDUkazatel] [smallint] NOT NULL,
    [Cas] [datetime2](0) NOT NULL,
    [Hodnota] [real] NULL,
    [HodnotaMax] [real] NULL,
    [HodnotaMin] [real] NULL,
 CONSTRAINT [PK_Data] PRIMARY KEY CLUSTERED 
(
    [IDUkazatel] ASC,
    [Cas] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

ALTER TABLE [dbo].[PenData]  WITH NOCHECK ADD  CONSTRAINT [FK_Data_Ukazatel] FOREIGN KEY([IDUkazatel])
REFERENCES [dbo].[Ukazatel] ([IDUkazatel])

ALTER TABLE [dbo].[PenData] CHECK CONSTRAINT [FK_Data_Ukazatel]

Nó chứa cca 211 hàng hàng.

Tôi chạy theo tuyên bố sau:

DECLARE @t1 DATETIME;
DECLARE @t2 DATETIME;

SET @t1 = GETDATE();
SELECT min(cas) from PenData p WHERE IDUkazatel=24
SELECT min(cas) from PenData p WHERE IDUkazatel=25
SET @t2 = GETDATE();
SELECT DATEDIFF(millisecond,@t1,@t2) AS elapsed_ms;


SET @t1 = GETDATE();
SELECT min(cas) from PenData p WHERE IDUkazatel=24 OR IDUkazatel=25 
SET @t2 = GETDATE();
SELECT DATEDIFF(millisecond,@t1,@t2) AS elapsed_ms;

Kết quả được hiển thị ở đây:

Kế hoạch thực hiện

CHỌN thứ ba cũng tải nhiều dữ liệu hơn vào bộ nhớ cache của SQL Server.

Tại sao CHỌN thứ ba chậm hơn nhiều (8,5 giây) sau đó hai CHỌN đầu tiên (16 ms)? Làm cách nào tôi có thể cải thiện hiệu suất của lựa chọn thứ ba bằng OR? Tôi muốn chạy theo lệnh SQL nhưng dường như với tôi rằng việc tạo con trỏ và chạy các truy vấn riêng biệt nhanh hơn nhiều so với một lần chọn trong trường hợp này.

 SELECT MIN(cas) from PenData p WHERE IDUkazatel IN (SELECT IDUkazatel FROM  ...)

BIÊN TẬP

Như David đề nghị tôi đã di chuột qua mũi tên béo:

FatArrow

Câu trả lời:


11

Đối với hai truy vấn đầu tiên, tất cả những gì phải làm là quét trong chỉ mục được nhóm sang mục nhập đầu tiên cho giá trị đó IDUkazatel- vì thứ tự của chỉ mục mà hàng sẽ là giá trị thấp nhất cho cas cho giá trị đó IDUkazatel.

Trong truy vấn thứ hai, tối ưu hóa này không phải là giá trị và có lẽ nó đang tìm kiếm hàng đầu tiên để IDUkazatel=24sau đó quét chỉ mục cho đến hàng cuối cùng IDUkazatel=25để tìm giá trị tối thiểu của castất cả các hàng đó.

Nếu bạn di chuột qua mũi tên mập đó, bạn sẽ thấy nó đang đọc nhiều hàng (chắc chắn là tất cả 24 hàng, có lẽ tất cả những hàng cho 25), trong khi các mũi tên mỏng trong đầu ra kế hoạch cho hai hàng kia chỉ hiển thị tophành động khiến nó chỉ hoạt động xem xét một hàng.

Bạn có thể thử chạy từng truy vấn và sau đó lấy mức tối thiểu cho mức tối thiểu được tìm thấy:

SELECT MIN(cas)
FROM   (
        SELECT cas=MIN(cas) FROM PenData p WHERE p.IDUkazatel = 24
        UNION ALL
        SELECT cas=MIN(cas) FROM PenData p WHERE p.IDUkazatel = 25
    ) AS minimums

Điều đó nói rằng, có vẻ như bạn có một bảng với IDUkazatelcác giá trị hơn là một ORmệnh đề rõ ràng . Mã dưới đây sẽ hoạt động với sự sắp xếp đó, chỉ cần thay thế tên bảng @Tbằng tên của bảng chứa IDUkazatelcác giá trị:

SELECT 
    MinCas = MIN(CA.PartialMinimum)
FROM @T AS T
CROSS APPLY 
(
    SELECT 
        PartialMinimum = MIN(PD.Cas)
    FROM dbo.PenData AS PD
    WHERE 
        PD.IDUkazatel = T.IDUkazatel
) AS CA;

Trong một thế giới lý tưởng, trình tối ưu hóa truy vấn SQL Server sẽ thực hiện việc viết lại này cho bạn, nhưng không phải lúc nào nó cũng xem xét tùy chọn này ngày hôm nay.


Bạn có thể viết lại cái cuối cùng mà không cần bảng dẫn xuất SELECT TOP (1) min_cas=MIN(CAS) ... ORDER BY min_cas;(nhưng tôi đoán kế hoạch sẽ giống với bảng của bạn.)
ypercubeᵀᴹ
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.