简化,我有两个表,contacts
和donotcall
CREATE TABLE contacts
(
id int PRIMARY KEY,
phone1 varchar(20) NULL,
phone2 varchar(20) NULL,
phone3 varchar(20) NULL,
phone4 varchar(20) NULL
);
CREATE TABLE donotcall
(
list_id int NOT NULL,
phone varchar(20) NOT NULL
);
CREATE NONCLUSTERED INDEX IX_donotcall_list_phone ON donotcall
(
list_id ASC,
phone ASC
);
我想看看哪些联系人与DoNotCall手机的特定列表中的电话号码相匹配。
为了加快查询速度,我在donotcall
和list_id
上编入了phone
索引。
当我进行以下JOIN时需要很长时间(例如9秒):
SELECT DISTINCT c.id
FROM contacts c
JOIN donotcall d
ON d.list_id = 1
AND d.phone IN (c.phone1, c.phone2, c.phone3, c.phone4)
如果我在每个手机领域单独左键加速,它运行得更快(例如1.5秒):
SELECT c.id
FROM contacts c
LEFT JOIN donotcall d1
ON d1.list_id = 1
AND d1.phone = c.phone1
LEFT JOIN donotcall d2
ON d2.list_id = 1
AND d2.phone = c.phone2
LEFT JOIN donotcall d3
ON d3.list_id = 1
AND d3.phone = c.phone3
LEFT JOIN donotcall d4
ON d4.list_id = 1
AND d4.phone = c.phone4
WHERE
d1.phone IS NOT NULL
OR d2.phone IS NOT NULL
OR d3.phone IS NOT NULL
OR d4.phone IS NOT NULL
我的假设是第一个代码段运行缓慢,因为它没有使用donotcall
上的索引
那么,如何对多列进行连接并仍使用索引?
答案 0 :(得分:6)
SQL Server可能认为使用索引解析IN (c.phone1, c.phone2, c.phone3, c.phone4)
太贵了。
您可以使用提示测试索引是否更快:
SELECT c.*
FROM contacts c
JOIN donotcall d with (index(IX_donotcall_list_phone))
ON d.list_id = 1
AND d.phone IN (c.phone1, c.phone2, c.phone3, c.phone4)
根据您发布的查询计划,它显示第一个计划估计产生4万行,但它只返回21行。第二个计划估计1行(当然也会返回21行。)
您的statistics是最新的吗?过时的统计数据可以解释查询分析器做出错误选择的原因。统计数据应自动更新或每周更新一次。使用以下方法检查统计信息的年龄:
select object_name(ind.object_id) as TableName
, ind.name as IndexName
, stats_date(ind.object_id, ind.index_id) as StatisticsDate
from sys.indexes ind
order by
stats_date(ind.object_id, ind.index_id) desc
您可以手动update them使用:
EXEC sp_updatestats;
答案 1 :(得分:0)
由于这种糟糕的数据库结构,UNION ALL查询可能是最快的。