[英]SQL Server why is index not used with OR
我一直在研究索引並試圖了解它們的工作原理以及如何使用它們來提高性能,但我遺漏了一些東西。
我有下表:
人 :
| Id | Name | Email | Phone |
| 1 | John | E1 | P1 |
| 2 | Max | E2 | P2 |
我正在嘗試找到索引Email
和Phone
列的最佳方法,因為查詢將(大部分時間)是表格的形式
[1] SELECT * FROM Person WHERE Email = '...' OR Phone = '...'
[2] SELECT * FROM Person WHERE Email = ...
[3] SELECT * FROM Person WHERE Phone = ...
我認為最好的方法是使用兩列創建單個索引:
CREATE NONCLUSTERED INDEX [IX_EmailPhone]
ON [dbo].[Person]([Email], [PhoneNumber]);
但是,使用上面的索引,只有查詢[2]受益於索引查找,其他查詢[2]使用索引掃描。
我還嘗試創建多個索引:一個包含兩列,一個用於電子郵件,一個用於電子郵件。 在這種情況下,[2]和[3]使用seek,但[1]繼續使用scan。
為什么數據庫不能使用索引或? 考慮到查詢,該表的最佳索引方法是什么?
為每列創建單獨的索引。
通過使用提示,我們可以強制優化器使用/不使用索引,因此您可以檢查執行計划,了解所涉及的性能並了解每個路徑的含義。
瀏覽我的演示並考慮以下場景中每條路徑所涉及的工作 -
只有少數行滿足條件j = 123。
只有少數行滿足條件k = 456。
大多數行滿足條件j = 123。
大多數行滿足條件k = 456。
只有少數行滿足條件j = 123。
大多數行滿足條件k = 456。
試着想一下你為每個場景選擇的路徑。
請隨時提問。
演示
;with t(n) as (select 0 union all select n+1 from t where n < 999)
select 1+t0.n+1000*t1.n as i
,floor(rand(cast (newid() as varbinary))*1000) as j
,floor(rand(cast (newid() as varbinary))*1000) as k
into t
from t t0,t t1
option (maxrecursion 0)
;
create index t_j on t (j);
create index t_k on t (k);
update statistics t (t_j)
update statistics t (t_k)
select *
from t (forcescan)
where j = 123
or k = 456
select *
from t (forceseek)
where j = 123
or k = 456
使用兩個單獨的索引,一個在(email)
,一個在(phone, email)
。
OR
非常困難。 如果您的條件通過AND
而不是OR
連接,那么您的索引將用於第一個查詢(但不是第三個查詢,因為phone
不是索引中的第一個鍵)。
您可以將查詢編寫為:
SELECT *
FROM Person
WHERE Email = '...'
UNION ALL
SELECT *
FROM Person
WHERE Email <> '...' AND Phone = '...';
SQL Server應為每個子查詢使用適當的索引。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.