Sql 为什么使用索引扫描而不是索引查找?

Sql 为什么使用索引扫描而不是索引查找?,sql,sql-server,clustered-index,Sql,Sql Server,Clustered Index,我在两个必须连接的大型表上创建了唯一的聚集索引,但这些索引没有被使用,查询计划证明了这一点。当我用提示强制使用这些索引时,会使用索引扫描,性能会变得更差。一个表的唯一键是第二个表的外键,这让我很困惑。这是模式。这两个表是LOC和POLLOC有700多万行,而POL有600多万行 CREATE TABLE [dbo].[LOC]( [acct_num] [char](30) NOT NULL, [cntr_num] [char](30) NOT NULL, [lob_cde

我在两个必须连接的大型表上创建了唯一的聚集索引,但这些索引没有被使用,查询计划证明了这一点。当我用提示强制使用这些索引时,会使用索引扫描,性能会变得更差。一个表的唯一键是第二个表的外键,这让我很困惑。这是模式。这两个表是
LOC
POL
LOC
有700多万行,而
POL
有600多万行

CREATE TABLE [dbo].[LOC](
    [acct_num] [char](30) NOT NULL,
    [cntr_num] [char](30) NOT NULL,
    [lob_cde] [char](2) NOT NULL,
    [ste_locn_nme] [char](30) NOT NULL,
    [buldg_num] [char](20) NOT NULL,
    [prctr_cde] [char](3) NULL,
        ...more fields...
) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IDX_All] ON [dbo].[LOC] 
(
    [acct_num] ASC,
    [cntr_num] ASC,
    [lob_cde] ASC,
    [buldg_num] ASC,
    [prctr_cde] ASC,
    [spcl_cond_1_id] ASC,
    [spcl_cond_2_id] ASC,
    [spcl_cond_3_id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

CREATE UNIQUE CLUSTERED INDEX [IDX_LOC_PKEY] ON [dbo].[LOC] 
(
    [acct_num] ASC,
    [lob_cde] ASC,
    [prctr_cde] ASC,
    [cntr_num] ASC,
    [ste_locn_nme] ASC,
    [buldg_num] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

... more non-unique indices on LOC, each on single columns: buldg_num, prctr_cde, acct_num

CREATE TABLE [dbo].[POL](
    [acct_num] [char](30) NOT NULL,
    [cntr_num] [char](30) NOT NULL,
    [lob_cde] [char](2) NOT NULL,
    [prctr_cde] [char](3) NULL,
        ...more fields...
) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IDX_All] ON [dbo].[POL] 
(
    [acct_num] ASC,
    [cntr_num] ASC,
    [lob_cde] ASC,
    [prctr_cde] ASC,
    [acct_nme] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

CREATE UNIQUE CLUSTERED INDEX [IDX_POL_PKEY] ON [dbo].[POL] 
(
    [acct_num] ASC,
    [lob_cde] ASC,
    [prctr_cde] ASC,
    [cntr_num] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

... more non-unique indices on POL, each on single columns: cntr_num, prctr_cde
如您所见,POL表的唯一键的四个字段(
acct_num、lob_cde、prctr_cde、cntr_num
)是
LOC
表主键的前四列。下面是我想要运行的一个查询,就像许多将连接这两个表的查询一样:

select 
      [Easy matches] = COUNT(*)
FROM LOC INNER JOIN POL ON (
        LOC.acct_num = POL.acct_num 
    AND LOC.lob_cde = POL.lob_cde 
    AND LOC.prctr_cde = POL.prctr_cde
    AND LOC.cntr_num = POL.cntr_num)
在没有提示的情况下,它喜欢使用每个表中的
IDX\u prctr\u cde
索引。
prctr\u cde
列不是很有选择性;
LOC
POL
表中只有七个不同的值。如果我提示查询应该使用
IDX\u cntr\u num
索引,我会获得良好的性能,因为它是一个高度选择性的列(每个表中有600多万个不同的值)
acct\u num
几乎与
cntr num
,而且具有超过600万个不同的值

为什么默认情况下使用非选择性索引?为什么切换到使用唯一的聚集索引会使查询运行得慢得多?(速度慢10倍、20倍甚至30倍。)

注意:我使用的提示是:

OPTION ( 
        TABLE HINT(POL, INDEX (IDX_POL_PKEY)),
        TABLE HINT(LOC, INDEX (IDX_LOC_PKEY))
       )

注意:我使用的是SQL Server 2005和SQL Server 2008。

好吧,因为您需要
计数(*)
,SQL Server必须以某种方式扫描所有行。为了尽可能减少需要读取的数据量,仅为了确定计数,查询优化器将尝试使用尽可能最小的索引—每个索引项的字节数最少的索引,这将导致从磁盘读取的字节数最少,从而扫描整组数据。这对于其中一个表的索引扫描是有意义的。当它扫描该索引时,为什么不使用索引查找另一个表来查找匹配的行呢?我试着在连接中只提示一个表,但我仍然扫描了两个表。你的聚集索引太大了!115字节-对于单个条目!这真是太糟糕了。集群键被复制到每个非集群索引中——这是SQL Server中重复最多的数据结构。理想情况下,它应该是一个4字节的
INT
或类似的东西-115字节是巨大的-难怪您的查询(尤其是在聚集索引上)需要很长时间。。。这样,您拥有的每个非聚集索引也将包括构成聚集键的所有6列—全部115个字节!因此,即使您在
lob_cde
上的索引是
char(2)
,因此2个字节,也不会是700万乘以2字节=1400万字节,实际上是700万乘以115字节=8.05亿字节。真是浪费!这就是原因。我不知道聚集索引键会被添加到其他索引中。哎哟我想我会把集群indexc变成非集群indexc,或者干脆放弃它。