【问题标题】:SQL Server doesn't use a suggested indexSQL Server 不使用建议的索引
【发布时间】:2018-05-12 15:13:48
【问题描述】:

首先,我使用的是:Microsoft SQL Server 2012 (SP1) - 11.0.3000.0 (X64)

我创建了一个如下所示的表:

 create table dbo.pos_key
 ( keyid                           int identity(1,1)     not null
 , systemid                        int                   not null
 , partyid                         int                   not null
 , portfolioid                     int                       null
 , instrumentid                    int                   not null
 , security_no                     decimal(10,0)             null
 , entry_date                      datetime              not null
 )

keyid 是一个聚集的主键。我的表有大约 144,000 行。目前systemId波动不大,除了1之外每一行都是一样的。 现在我执行以下查询:

select *
  from pos_key
 where systemid = 33000
   and portfolioid = 150444
   and instrumentid = 639

在聚集索引扫描后返回 1 行。 [pos_key].[PK_pos_key] 执行计划说预期的行数是 1.082

SQL Server 很快建议我添加索引。

 CREATE NONCLUSTERED INDEX IDX_SYS_PORT_INST
 ON [dbo].[pos_key] ([systemid],[portfolioid],[instrumentid])

所以我这样做并再次运行查询。 令人惊讶的是,SQL-server 并没有使用新索引,而是再次进行相同的聚集索引扫描,但现在它声称期望 4087 行!然而,这一次并没有建议任何新的索引。

为了让它使用新索引,我做了以下操作:

  • 更新表统计信息(更新统计信息)
  • 更新的索引统计信息(更新统计信息)
  • 已删除与此查询相关的缓存执行计划 (DBCC FREEPROCCACHE)

不走运,SQL Server 总是进行集群扫描,预计 4087 行。

索引统计如下所示:

All Density      Average Length   Columns                         
----------------------------------------------------------------------------
0.5              4                systemid                        
6.095331E-05     7.446431         systemid, portfolioid           
1.862301E-05     11.44643         systemid, portfolioid, instrumentid
6.9314E-06       15.44643         systemid, portfolioid, instrumentid, keyid

奇怪的是,我一夜之间离开了这个,早上再次运行查询,BAMM 现在它命中了索引。我删除了索引,运行了选择,然后再次创建了索引。现在 SQL Server 又回到了预期的 4087 行和聚集索引扫描。

那么我错过了什么。该索引显然有效,但 SQL Server 不想立即使用它。

  • systemId 的波动是否会造成麻烦?
  • DBCC FREEPROCCACHE 是否不足以摆脱缓存的执行计划?
  • SQL-Server 的方式是不是很神秘?

【问题讨论】:

  • 您为每个谓词分别获得的估计行数是多少?即,如果您查看三个查询的估计计划,每个查询都有一个条件?
  • 你能在你的表格中插入一个文件并共享它吗?我也尝试用与您的分布相似的分布填充表格,并且 1)没有索引建议 2)3 列的密度正确反映了情况,在我的情况下估计也是正确的
  • @MartinSmith 执行的行数如下:使用 SystemId:144270 使用 PortfolioId:26730
  • @MartinSmith 执行的行数如下所示: 使用 SystemId:144270 = 100% 使用 PortfolioId:26730 = 18,53% 使用 InstrumentId:16446 = 11,40% 这些数字恰好与如果我在按组合 ID 分组时做了最大计数()。然而,按所有 3 分组并取 count() 的最大值并没有给出 4087。然而,第三名非常接近 4074。
  • 144270 * (144270/144270.0 * 26730/144270.0 * 16446/144270.0)3047,因此基于这些值是独立的假设,您会期望这是估计值。这些值不是独立且相关的吗?

标签: sql-server indexing querying


【解决方案1】:

使用复合索引和相等谓词中使用的所有列,首先指定最具选择性的列(此处为portfolieid)。 SQL Server 只为第一列维护一个直方图。

首先选择较少的列,SQL Server 可能高估了行数并选择了聚集索引扫描,而不是认为它更有效,因为您选择了所有列。

【讨论】:

  • SQL Server 将自动在其他列上创建统计信息。没有理由只使用那个无意义的二值直方图。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多