当您想要在大型表中选择大部分数据时,低选择性覆盖索引是否有用?

时间:2013-11-08 17:52:44

标签: sql sql-server database indexing

正在运行: SQL Server 2008 R2 标准。虽然我认为这是所有数据库的问题,而不仅仅是SQL Server。

背景:我一直听到/读/被告知索引的前沿应该是高度选择性的。当你有查询寻求特定值或一小组价值 - 产品ID或类似的东西时,这是有道理的。

一般问题:有时高选择性索引有用吗?

例如:我有一个包含3.5亿行的表格。该表包含一堆价格。该表格包含以下列:

  • priceId - 表格上的聚集索引
  • warehouseId - fk到10个仓库中的一个,平均分布在 150米行
  • algorithmId - 用于计算价格的23种算法中的一种,平均分布在150米行中
  • priceDate - 我们上次计算价格的日期
  • productId

然后我运行这个查询:

select productId 
from price 
where warehouseId = 1 
    and algorithmId = 1 
order by priceDate

具体问题:我不会从这样的索引中受益吗?

create nonclustered index ix_p 
on price (warehouseId, algorithmId, priceDate) includes (productId)

似乎我会受益于b / c我已经创建了一个覆盖索引,其中过滤列很好地组织起来,这样SQL Server就可以一次分割出大量的块并按priceDate排序。那有意义吗?它有效吗?

注意:我会试一试,让你知道我发现了什么。

2 个答案:

答案 0 :(得分:0)

简短的回答 - 是的,但你的存储量基本上增加了一倍。

答案很长:

我在具有1.5亿行数据的SQL 2012 VirtualBox Server 2008虚拟机上测试了这一点。文件组存储在VM映像上,该映像位于与固态驱动器的USB 3.0连接上(顺序读取似乎约为250 mb / s,写入速度约为150 mb / s)。

我用伪随机日期建立了一个表格& productIds,仓库从1-10均匀分布,并且算法从1-23均匀分布。 (基本上我在SSIS中编写了一个加载数据的源脚本组件)。

表存储空间大约为4.7 GB,主键priceid上有聚簇索引。

运行此查询:

select productId 
from price 
where warehouseId = 1 
    and algorithmId = 1 
order by priceDate

约30秒内返回约100万行。 计划表示聚集索引扫描加上排序(按priceDate排序)。

然后我添加了这个非聚集索引:

create nonclustered index ix_p 
on price (warehouseId, algorithmId, priceDate) include (productId)

此索引几乎与表格一样大 - 约为4.3 GB。

添加非聚集索引消除了priceDate上的SORT步骤,并更改为执行非聚簇索引寻求访问数据。创建此索引需要11分钟。

相同查询: 在大约4秒内返回约100万行。 计划表示非聚集索引搜索。

我认为这样做的最重要的事情就是创建两个数据副本 - 一个在聚簇索引结构中,另一个在“非聚集”结构中。

我希望插入大约需要两倍的时间,因为现在你必须为每个插入创建基本上两行。

您是否定期对此表进行更新?可能还有其他一些可能有用的策略。

答案 1 :(得分:0)

我刚刚完成了一个类似于我在问题中描述的非聚集索引。表有101,308,183行,每行61个字节。以下是一些结果:

使用当前的“选择性”索引,并将productId和仓库作为键:

  • 返回461,000行
  • 平均运行时间:2分36秒
  • 扫描次数:116
  • 逻辑阅读: 9,870,354
  • 物理读物: 20,086
  • 预读阅读:967,324

使用新的非选择性索引,如我原来的问题所述:

  • 返回461,000行
  • 平均运行时间:47秒
  • 扫描次数:76
  • 逻辑阅读: 109,934
  • 物理读取: 0
  • 预读读取:1

总而言之,一个非选择性指数给我 90次逻辑读数(987万到110k),物理读数减少100%(从20k到0)和预读读取 100%(967k到0)。

同样,我认为这是因为SQL已经对所有数据进行了排序,因此很容易切断(即排除)大块数据。因为索引涵盖了这个查询(这是我们在生产环境中运行的两个查询之一),所以我们不会浪费时间进行密钥查找。