sql-server - 更新非聚集索引有时会在 dm_db_index_usage_stats 中注册 SEEK 吗?

标签 sql-server indexing sql-server-2012

我们在 uniqueidentifier 上设计了一个糟糕的索引。我们在我们的系统上找不到任何有理由使用它的查询,但这并不意味着连接应用程序绝对不需要它。

该表有超过 6 亿行,其聚集索引不是唯一的。每个聚集索引值被复制超过 100 万次。由于表的大小,我们对删除索引感到紧张,因为重新创建它非常困难。没有 key 。

在 dm_db_index_usage_stats 中没有针对它的扫描或查找,但是 dm_db_index_usage_stats 确实显示了针对它的少量搜索。

我们搜索了查询计划,只找到了它作为更大的聚集索引更新的一部分被引用的时间;没有明确的索引寻求。

它们是否可以作为统计更新的一部分、索引更新的一部分完成,或者查询引擎是否有可能在更深层次的自联接计算中使用它,因为它是表中唯一的唯一字段?

如果有人可以解释搜索,我们也许可以放弃它并获得性能提升。

最佳答案

SQL Server 索引本质上是表中已经存在的数据的副本,以不同的方式排序和过滤以提高执行查询的性能。搜索、扫描和查找运算符用于访问 SQL Server 索引。

寻求运营商 – Seek 运算符使用 SQL Server 搜索索引的能力从聚集或非聚集索引中获取行,并且查找可以是物理运算符,也可以是逻辑运算符。索引查找仅处理符合条件的行和包含这些符合条件的行的页面,因此查找成本较低。简单来说,就是从表中检索刚刚选定的行。

扫描运算符(operator) – Scans 操作符扫描聚集索引,它旨在处理扫描表中的每一行,而不管该行是否合格。扫描运算符对于小表或在大多数行都符合条件的情况下可能很有效。简单来说,扫描从表中检索所有行。

查找运算符 – 查找运算符,用于从非聚集索引检索的结果集中检索非键数据。从非聚集索引检索行后,查找用于从这些行检索列信息。

虽然正确使用 SQL Server 索引可以提高已执行查询的性能,从而提高 SQL Server 的性能,但如果在需要时不正确地设置它们或未在需要的地方设置它们,则会显着降低已执行查询的性能。此外,具有查询不使用的不必要索引也可能存在问题。

SQL Server 索引是提高 SELECT 查询性能的绝佳工具,但同时,SQL Server 索引对数据更新也有负面影响。 INSERT、UPDATE 和 DELETE 操作会导致索引更新,从而复制表中已存在的数据。因此,这会增加事务和查询执行的持续时间,并且通常会导致锁定、阻塞、死锁和非常频繁的执行超时。对于大型数据库或表,存储空间也会受到冗余索引的影响。任何 SQL Server DBA 的一个关键目标是维护索引,包括创建所需的索引,但同时删除未使用的索引。

查找未使用的索引

SQL Server 通过动态管理 View (DMV) 提供大量索引信息。 dm_db_index_usage_stats DMV 显示有关索引使用的基本信息,它可以成为识别未使用的 SQL Server 索引的有用工具。第一次使用索引时,会在 dm_db_index_usage_stats 中创建一个新行。 DMV 并随后在每次使用索引时更新。但是,与每个 DMV 一样,dm_db_index_usage_stats 中存在的数据仅包含自上次 SQL Server 服务重新启动以来的数据(SQL Server 服务重新启动会重置 DMV 中的数据)。因此,自上次 SQL Server 重新启动后有足够的时间来正确确定哪些索引适合删除,这一点至关重要。

可用于获取 SQL Server 中未使用索引列表的简单查询(未在任何搜索、扫描或查找操作中使用的更新索引)如下:

SELECT
    objects.name AS Table_name,
    indexes.name AS Index_name,
    dm_db_index_usage_stats.user_seeks,
    dm_db_index_usage_stats.user_scans,
    dm_db_index_usage_stats.user_updates
FROM
    sys.dm_db_index_usage_stats
    INNER JOIN sys.objects ON dm_db_index_usage_stats.OBJECT_ID = objects.OBJECT_ID
    INNER JOIN sys.indexes ON indexes.index_id = dm_db_index_usage_stats.index_id AND dm_db_index_usage_stats.OBJECT_ID = indexes.OBJECT_ID
WHERE
    AND
    dm_db_index_usage_stats.user_lookups = 0
    AND
    dm_db_index_usage_stats.user_seeks = 0
    AND
    dm_db_index_usage_stats.user_scans = 0
ORDER BY
    dm_db_index_usage_stats.user_updates DESC

上面的查询返回所有类型的所有未使用的索引。这个查询经常可以在互联网上找到,但不是一个理想/完整的选项。通过使用这样的查询来查找和清理未使用的索引可能会导致意外行为,因为此查询在收集未使用的索引数据时没有考虑主键和唯一键约束。主键和唯一键约束索引都可能“未使用”,但删除这些索引可能会出现问题。为了防止出现这种情况,必须通过在 WHERE 之后添加两行代码来优化上面的查询,以排除主键和唯一键被列为未使用和可能被删除的情况。
SELECT
    objects.name AS Table_name,
    indexes.name AS Index_name,
    dm_db_index_usage_stats.user_seeks,
    dm_db_index_usage_stats.user_scans,
    dm_db_index_usage_stats.user_updates
FROM
    sys.dm_db_index_usage_stats
    INNER JOIN sys.objects ON dm_db_index_usage_stats.OBJECT_ID = objects.OBJECT_ID
    INNER JOIN sys.indexes ON indexes.index_id = dm_db_index_usage_stats.index_id AND dm_db_index_usage_stats.OBJECT_ID = indexes.OBJECT_ID
WHERE
    indexes.is_primary_key = 0 -- This condition excludes primary key constarint
    AND
    indexes. is_unique = 0 -- This condition excludes unique key constarint
    AND
    dm_db_index_usage_stats. user_lookups = 0
    AND
    dm_db_index_usage_stats.user_seeks = 0
    AND
    dm_db_index_usage_stats.user_scans = 0
ORDER BY
    dm_db_index_usage_stats.user_updates DESC

上述查询列出了所有非主键和唯一键的未使用查询,但也列出了 SQL Server 未使用的所有未使用索引。 dm_db_index_usage_stats DMV 中的 user_updates 列正在计算索引更新的位置,因为应用程序对数据进行了一些更改,因此更新了索引。要做到这一点dm_db_index_usage_stats.user_updates <> 0应将条件添加到先前的脚本中。
SELECT
    objects.name AS Table_name,
    indexes.name AS Index_name,
    dm_db_index_usage_stats.user_seeks,
    dm_db_index_usage_stats.user_scans,
    dm_db_index_usage_stats.user_updates
FROM
    sys.dm_db_index_usage_stats
    INNER JOIN sys.objects ON dm_db_index_usage_stats.OBJECT_ID = objects.OBJECT_ID
    INNER JOIN sys.indexes ON indexes.index_id = dm_db_index_usage_stats.index_id AND dm_db_index_usage_stats.OBJECT_ID = indexes.OBJECT_ID
WHERE
    indexes.is_primary_key = 0 --This line excludes primary key constarint
    AND
    indexes. is_unique = 0 --This line excludes unique key constarint
    AND 
    dm_db_index_usage_stats.user_updates <> 0 -- This line excludes indexes SQL Server hasn’t done any work with
    AND
    dm_db_index_usage_stats. user_lookups = 0
    AND
    dm_db_index_usage_stats.user_seeks = 0
    AND
    dm_db_index_usage_stats.user_scans = 0
ORDER BY
    dm_db_index_usage_stats.user_updates DESC

因此,既然已识别并列出未使用的 SQL Server 索引,就可以确定可以安全删除哪些索引,但同样必须非常小心地进行。

关于sql-server - 更新非聚集索引有时会在 dm_db_index_usage_stats 中注册 SEEK 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52821163/

相关文章:

sql-server - 普通的 SQL Server 索引是否包含主键值?

oracle - 在 Oracle 中如何检测表上的特定列是否有索引?

ssis - 在 SSISDB 中无法创建新文件夹

elasticsearch - 升级到 Elastic Search NEST 7.0.1 破坏了检查索引是否存在的代码

sql-server - 缺口和岛屿?或不?

sql - DISTINCT 值的表索引

.net - Entity Framework 性能问题

sql - 如何在单个语句中获取 Northwind 数据库中 Order Details 表中每个产品的总销售额?

sql-server - 重用检查约束

sql-server - 使用 BCP 将数据复制到 Azure 时未显示任何错误,但未传输任何数据