正在运行: 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
排序。那有意义吗?它有效吗?
注意:我会试一试,让你知道我发现了什么。
答案 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和仓库作为键:
使用新的非选择性索引,如我原来的问题所述:
总而言之,一个非选择性指数给我 90次逻辑读数(987万到110k),物理读数减少100%(从20k到0)和预读读取 100%(967k到0)。
同样,我认为这是因为SQL已经对所有数据进行了排序,因此很容易切断(即排除)大块数据。因为索引涵盖了这个查询(这是我们在生产环境中运行的两个查询之一),所以我们不会浪费时间进行密钥查找。