Sql-Server
與單獨的 SELECT 相比,使用 OR 條件的索引查找要慢得多
基於這些問題和給出的答案:
SQL 2008 Server - 性能損失可能與非常大的表有關
具有歷史數據的大型表分配了過多的 SQL Server 2008 Std。記憶體 - 其他數據庫的性能損失
我在數據庫 SupervisionP 中有一個表,定義如下:
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]
它包含 cca 2.11 億行。
我執行以下語句:
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;
結果顯示在這裡:
第三個 SELECT 還將更多數據載入到 SQL Server 記憶體記憶體中。
為什麼第三個 SELECT 比前兩個 SELECT(16 毫秒)慢得多(8.5 秒)?如何使用 OR 提高第三個選擇的性能?我想執行以下 SQL 命令,但在我看來,在這種情況下,創建游標和執行單獨的查詢比單個選擇要快得多。
SELECT MIN(cas) from PenData p WHERE IDUkazatel IN (SELECT IDUkazatel FROM ...)
編輯
正如大衛建議的那樣,我將滑鼠懸停在粗箭頭上:
對於前兩個查詢,它所要做的就是在聚集索引中掃描到該值的第一個條目
IDUkazatel
- 因為索引的順序,該行將是該值的 cas 的最低值IDUkazatel
。在第二個查詢中,此優化不是價值,它可能正在尋找第一行,
IDUkazatel=24
然後向下掃描索引,直到最後一行找到所有這些行IDUkazatel=25
的最小值。cas
如果您將滑鼠懸停在那個粗箭頭上,您會看到它正在讀取許多行(當然是所有 24 行,也可能是所有 25 行),而其他兩個的計劃輸出中的細箭頭顯示
top
導致它僅考慮一行。您可以嘗試執行每個查詢,然後獲取找到的最小值的最小值:
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
也就是說,您似乎有一個包含
IDUkazatel
值而不是顯式OR
子句的表。下面的程式碼將使用這種安排,只需將表名替換為@T
包含IDUkazatel
值的表名: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;
在理想情況下,SQL Server 查詢優化器會為您執行此重寫,但現在並不總是考慮此選項。