[英]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.