Sql server 在连接时使用索引';对多个列进行排序

Sql server 在连接时使用索引';对多个列进行排序,sql-server,sql-server-2008,join,indexing,Sql Server,Sql Server 2008,Join,Indexing,简而言之,我有两个表,联系人和不打电话 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 var

简而言之,我有两个表,
联系人
不打电话

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电话的特定列表中的电话号码相匹配。 为了更快地查找,我在
list\u id
phone
上索引了
donotcall

当我进行以下连接时,需要很长时间(例如9秒):

而如果我分别在每个电话字段上留下JOIN,它会运行得更快(例如1.5秒):

我的假设是,第一个代码段运行缓慢,因为它没有利用
donotcall
上的索引

那么,如何对多个列进行连接,并且仍然让它使用索引呢?

SQL Server可能认为在(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)
从您发布的查询计划中,它显示第一个计划估计会产生40k行,但它只返回21行。第二个计划估计1行(当然也返回21行)

你的电脑是最新的吗?过时的统计信息可以解释查询分析器做出错误选择的原因。统计数据应自动更新或在每周作业中更新。使用以下信息检查统计数据的年龄:

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
您可以手动使用:

EXEC sp_updatestats;

使用这种糟糕的数据库结构,UNION ALL查询可能最快。

好建议。我试着添加这个暗示。然而,这并没有改变任何事情。左连接版本仍然要快得多。SQL server似乎无法使用索引解析代码。您是否尝试过比较查询计划?(菜单查询,然后包括实际执行计划。)我正在尝试这样做,但我在分析查询计划方面经验很少。从我所看到的,左连接解决方案非常简单,使用4个哈希匹配(右外部连接)。单连接解决方案的做法完全不同。两个嵌套循环(内部联接),首先是索引,然后是联系人表。是否有免费的在线服务允许您上载和可视化查询计划以与其他人共享?您可以将其导出为XML并将其加载。其他人可以使用免费软件可视化该计划,但实际上您需要做的是修复datbase结构。您不应该有phone1、phone2、phone3、phone4-这表示您需要一个子表。@HLGEM:注意点。如果我有选择的话,我也会做出不同的选择。但有时你会被其他人创建的结构所困扰,而没有重构的希望。虽然UNION ALL目前的性能比single JOIN解决方案好,但它比LEFT JOIN解决方案慢一点。
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
EXEC sp_updatestats;