JOIN对多列时使用索引

时间:2013-09-04 12:37:44

标签: sql-server sql-server-2008 join indexing

简化,我有两个表,contactsdonotcall

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手机的特定列表中的电话号码相匹配。 为了加快查询速度,我在donotcalllist_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)  

Screenshot of execution plan

Execution plan on Pastebin

如果我在每个手机领域单独左键加速,它运行得更快(例如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

Screenshot of execution plan

Execution plan on Pastebin

我的假设是第一个代码段运行缓慢,因为它没有使用donotcall上的索引 那么,如何对多列进行连接并仍使用索引?

2 个答案:

答案 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查询可能是最快的。