索引sql server

Understanding indexing needs allows us to ensure that important processes run efficiently and that our server hardware is not being over-taxed by poorly performing queries.

了解索引需求使我们能够确保重要的流程高效运行,并且不会因查询性能不佳而使服务器硬件负担过重。

Collecting metrics on SQL Server index usage and missing index needs is critical to making smart decisions. To be truly proactive, though, we need to create a framework that allows us to quickly, efficiently, and regularly report on changes in indexing needs. With a system in place that can let us know when changes are needed, we can stay ahead of the optimization game and keep our customers happy!

收集有关SQL Server索引使用情况和缺少索引需求的指标对于做出明智的决定至关重要。 但是,要真正主动,我们需要创建一个框架,使我们能够快速,有效地并定期报告索引需求的变化。 有了一个可以让我们知道何时需要更改的系统,我们可以领先于优化游戏并保持客户满意!

介绍 (Introduction)

In previous articles, we built processes that regularly collect and aggregate data about missing SQL Server indexes and index usage statistics. Using this information, we can take additional steps to analyze this data and begin to make decisions based on it. Our goal is to build a reporting framework that can be run as often as desired where the results are stored in a table for easy retrieval.

在以前的文章中,我们构建了一些流程来定期收集和聚合有关缺失SQL Server索引和索引使用情况统计信息的数据。 使用此信息,我们可以采取其他步骤来分析此数据并开始根据该数据做出决策。 我们的目标是建立一个报告框架,该框架可以根据需要运行,并将结果存储在表格中以便于检索。

Once we report on index usage or missing SQL Server indexes, we can generate recommendations. Each time the process is run, we can check those recommendations and determine what has changed and if they have become more or less relevant over time. If we implemented a suggestion, we can then track the results and determine if it was a good idea, or perhaps not worth the cost.

一旦我们报告了索引使用情况或缺少SQL Server索引,便可以生成建议。 每次运行该流程时,我们都可以检查这些建议并确定已更改的内容以及它们是否随着时间的推移变得越来越相关。 如果我们实施了建议,则可以跟踪结果并确定这是一个好主意,还是不值得付出的代价。

The goal is to allow us to fully understand indexing on our important databases and to be able to proactively act on this information. Things change all the time, and being able to quantify that change before and after any database or application changes will allow us to stay on top of indexing. Our reaction times to change will be far better and, hopefully, we’ll avoid the pain of performance troubles that could have been prevented had we had more information available up-front.

目的是使我们能够充分理解重要数据库上的索引,并能够主动对这些信息采取行动。 事情一直在变化,并且能够在任何数据库或应用程序更改之前和之后量化该更改,这将使我们能够始终处于索引编制之上。 我们对变更的React时间将大大缩短,并且希望,如果我们能预先获得更多信息,我们将避免可能避免的性能问题。

SQL Server索引指标:回顾 (SQL Server Index Metrics: A Review)

In our previous work, we developed processes that collected data about index usage. First, we work with index usage statistics, which allow us to understand how often indexes are read or written to. Using this data, we can determine if an index is unused, minimally used, or misused. Once we understand those results, we can make a decision to drop the index (if unneeded) or alter it (if it could benefit from different columns).

在以前的工作中,我们开发了收集有关索引使用情况数据的流程。 首先,我们使用索引使用情况统计信息,该统计信息使我们能够了解读取或写入索引的频率。 使用此数据,我们可以确定索引是否未使用,使用最少或滥用。 一旦了解了这些结果,就可以决定删除索引(如果不需要)或更改索引(如果可以从不同的列中受益)。

Second, we collected data about missing indexes. As queries executed that could have benefitted from an index that does not exist, we report on this data so that we can later make decisions based on it. Many index recommendations are not worth the effort or overlap with each other, but all of this data allows us to better understand the workload that executes against our SQL Servers and decide what new indexes could be worth the resources.

其次,我们收集了有关缺失索引的数据。 由于执行的查询可能会从不存在的索引中受益,因此我们将报告此数据,以便以后可以基于该数据做出决策。 许多索引建议不值得付出努力或彼此重叠,但是所有这些数据使我们能够更好地了解针对我们SQL Server执行的工作负载,并确定哪些新索引可能值得这些资源。

Our first process populated tables called Index_Utilization_Details and Index_Utilization_Summary. The first table provided a snapshot of usage metrics each time the process was run. The second table was an aggregate that maintained overall usage counts over time, allowing for a better long-term view of index use. A brief snapshot of data in these tables looks like this:

我们的第一个过程填充了称为Index_Utilization_DetailsIndex_Utilization_Summary的表。 第一个表在每次运行过程时提供使用情况指标的快照。 第二张表是一个汇总表,可以随着时间的推移保持总体使用情况计数,从而可以更好地长期查看索引使用情况。 这些表中的数据简要快照如下所示:

Our second process also populated 2 tables: Missing_Index_Details and Missing_Index_Summary. These tables also offered both a point-in-time view of missing index metrics, as well as a longer-term aggregated view of overall use. Two views were created in order to provide additional metrics that can be derived from this data: v_Missing_Index_Details and v_Missing_Index_Summary. Here is a screenshot of some sample data returned from these views:

我们的第二个过程还填充了2个表: Missing_Index_DetailsMissing_Index_Summary 。 这些表还提供缺少索引指标的时间点视图以及整体使用情况的长期汇总视图。 为了提供可以从该数据派生的其他指标,创建了两个视图: v_Missing_Index_Detailsv_Missing_Index_Summary 。 这是从这些视图返回的一些示例数据的屏幕截图:

We can see via this data that we now have a wealth of data that is regularly collected and aggregated. We can choose to periodically review this data and decide if any actions need to be taken, but we can remove the manual element to that process and automate a process that inspects this data for us, putting the results into a central location. From here, we can report on it using an email, SSRS, or any other tool of our choosing.

通过这些数据我们可以看到,我们现在拥有大量定期收集和汇总的数据。 我们可以选择定期查看此数据并决定是否需要采取任何措施,但是我们可以删除该流程中的手动元素,并为我们自动检查该数据的流程,从而将结果放置在中心位置。 在这里,我们可以使用电子邮件,SSRS或我们选择的任何其他工具对此进行报告。

The remainder of this article will be concerned with making the best possible use of this data in order to easily report on potential indexing needs. At the same time, we will make an effort to go overboard and over-engineer a solution that is too complex to maintain or use.

本文的其余部分将关注如何最好地利用此数据,以便轻松报告潜在的索引需求。 同时,我们将努力解决过于复杂而难以维护或使用的解决方案。

实施SQL Server索引报告过程 (Implementing a SQL Server Index Reporting Process)

Before diving into our data, let’s put together a plan of attack. There are enough ways in which this process could be implemented that we should endeavor to stay focused on our ultimate goal, which is to report on important index needs. Here are is the basic structure of the stored procedure that we will be building:

在深入研究数据之前,让我们制定一个攻击计划。 有足够的方法可以实施此过程,我们应该努力保持专注于最终目标,即报告重要的索引需求。 这是我们将要构建的存储过程的基本结构:

        1. If so, make those recommendations. 如果是这样,请提出这些建议。
        1. If so, make those recommendations. 如果是这样,请提出这些建议。
      • If so, recommend that they be appropriately combined or duplicates removed. 如果是这样,建议将它们适当组合或删除重复项。
        1. If so, make those recommendations. 如果是这样,请提出这些建议。
        1. If so, then make those recommendations. 如果是这样,则提出这些建议。
    • If a recommendation was recommended before and not implemented, add details of that here. 如果之前曾提出建议而未实施建议,请在此处添加详细信息。
    • If a recommendation was implemented, then also make a note of that. 如果实施了建议,则也要记录下来。
    • Are they operating effectively? Report on this in a meaningful fashion. 他们运作有效吗? 以有意义的方式对此进行报告。
    • Are newly implemented missing indexes being utilized efficiently? 新实施的缺失索引是否得到有效利用?
    • Are indexes that were removed now showing up as significant missing indexes? 现在已删除的索引显示为重要的丢失索引吗?

Phew! That’s quite a bit of work we have to do! It sounds like a lot, but in reality, it’s a variety of checks against data that we have already collected in order to determine if it is significant enough to report back to us. With that (slightly) reassuring thought in mind, let’s begin building this thing!

! 这是我们要做的很多工作! 听起来很多,但实际上,它是对我们已经收集的数据进行的各种检查,以确定它是否足够重要以向我们报告。 带着(稍微)令人放心的想法,让我们开始构建这个东西!

SQL Server索引使用情况统计分析 (SQL Server Index Usage Stats Analysis)

The easiest metric to check for are indexes that are unused. The validation is easy, and the most important piece of data we would want to know is for how long they have been unused. We can view unused indexes like this:

最容易检查的指标是未使用的索引。 验证很容易,我们想知道的最重要的数据是未使用多长时间。 我们可以这样查看未使用的索引:


SELECTIndex_Utilization_Summary.Database_Name,Index_Utilization_Summary.[Schema_Name],Index_Utilization_Summary.Table_Name,Index_Utilization_Summary.Index_Name,Index_Utilization_Summary.Index_Utilization_Summary_Create_Datetime,Index_Utilization_Summary.Index_Utilization_Summary_Last_Update_Datetime,Index_Utilization_Summary.User_Update_Count_Total,Index_Utilization_Summary.Last_User_Update,DATEDIFF(DAY, Index_Utilization_Summary.Index_Utilization_Summary_Create_Datetime, Index_Utilization_Summary.Index_Utilization_Summary_Last_Update_Datetime) AS Days_Without_Reads
FROM IndexMetrics.Index_Utilization_Summary
WHERE Index_Utilization_Summary.User_Seek_Count_Total = 0
AND Index_Utilization_Summary.User_Scan_Count_Total = 0
AND Index_Utilization_Summary.User_Lookup_Count_Total = 0;

In addition to knowing that the index has not been read, the last column provides how many days have passed without any reads. While an index that has been unused for 6 months is a great candidate for removal, one that has only been unused for a day would need some more time to be sure that it is definitely not used. The results of this query are as follows:

除了知道尚未读取索引之外,最后一列还提供了多少天没有读取任何数据。 虽然已使用6个月的索引很适合删除,但仅使用1天的索引将需要更多时间来确保绝对不会使用。 该查询的结果如下:

Since the last seek/scan/lookup columns are NULL for unused indexes, we have to guess as to how long the index has been unused for. To be safe, we will only go back as far as our index metrics have been collected. Our results above show 5 indexes without any reads, 3 of which have been unused for almost a month and might be good candidates for removal. As always, an index unused for 2 months might be critical to some quarterly or yearly report that will bomb without it, so some level of verification of non-use is a good idea before making changes.

由于未使用的索引的最后一个搜索/扫描/查找列为NULL,因此我们必须猜测该索引已被使用了多长时间。 为了安全起见,我们只会回溯到我们收集到的指标指标。 我们上面的结果显示5个索引没有任何读取,其中3个已经使用了将近一个月,并且很可能会被删除。 与往常一样,未使用2个月的索引对于某些季度或年度报告可能至关重要,这些报告会在没有该索引的情况下爆炸,因此在进行更改之前一定程度的验证未使用是个好主意。

Next, we can look for indexes that are underused. These are indexes that are frequently written but rarely read. There is no universally accepted definition for what underused is, so for the sake of our demonstration, we will consider any index that has less than 2% reads. You may adjust this based on your comfort level with the schema and data that is being analyzed to be more conservative or return more data.

接下来,我们可以查找未充分使用的索引。 这些是经常写入但很少读取的索引。 对于未充分利用的定义没有普遍接受的定义,因此为了便于演示,我们将考虑读取次数少于2%的任何索引。 您可以根据您的舒适程度使用正在分析的方案和数据进行调整,以使其更加保守或返回更多数据。

The following query will return any indexes that have 2% or less reads, but greater than zero (separating this data from our previous query):

以下查询将返回读取次数小于或等于2%但大于零的所有索引(将这些数据与之前的查询分开):


WITH CTE_UNDERUSED_INDEXES AS (SELECT*,CAST(Index_Utilization_Summary.User_Seek_Count_Total + Index_Utilization_Summary.User_Scan_Count_Total + Index_Utilization_Summary.User_Lookup_Count_Total AS DECIMAL(19,2)) AS Read_Count,CAST(Index_Utilization_Summary.User_Seek_Count_Total + Index_Utilization_Summary.User_Scan_Count_Total + Index_Utilization_Summary.User_Lookup_Count_Total + User_Update_Count_Total AS DECIMAL(19,2)) AS Operation_CountFROM IndexMetrics.Index_Utilization_Summary )
SELECTCTE_UNDERUSED_INDEXES.Read_Count / CTE_UNDERUSED_INDEXES.Operation_Count AS Percent_Read,CTE_UNDERUSED_INDEXES.Index_Utilization_Summary_Create_Datetime,CTE_UNDERUSED_INDEXES.Index_Utilization_Summary_Last_Update_Datetime,CTE_UNDERUSED_INDEXES.Database_Name,CTE_UNDERUSED_INDEXES.[Schema_Name],CTE_UNDERUSED_INDEXES.Table_Name,CTE_UNDERUSED_INDEXES.Index_Name,CTE_UNDERUSED_INDEXES.User_Seek_Count_Total,CTE_UNDERUSED_INDEXES.User_Scan_Count_Total,CTE_UNDERUSED_INDEXES.User_Lookup_Count_Total,CTE_UNDERUSED_INDEXES.User_Update_Count_Total,CTE_UNDERUSED_INDEXES.Last_User_Seek,CTE_UNDERUSED_INDEXES.Last_User_Scan,CTE_UNDERUSED_INDEXES.Last_User_Lookup,CTE_UNDERUSED_INDEXES.Last_User_Update
FROM CTE_UNDERUSED_INDEXES
WHERE CTE_UNDERUSED_INDEXES.Read_Count / CASE WHEN CTE_UNDERUSED_INDEXES.Operation_Count = 0 THEN 1 ELSE CTE_UNDERUSED_INDEXES.Operation_Count END > 0
AND CTE_UNDERUSED_INDEXES.Read_Count / CASE WHEN CTE_UNDERUSED_INDEXES.Operation_Count = 0 THEN 1 ELSE CTE_UNDERUSED_INDEXES.Operation_Count END <= 0.02;

The CTE helps us to avoid divide-by-zero errors, and perform our calculations without too much repeated TSQL. The results look like this:

CTE帮助我们避免被零除的错误,并执行我们的计算而无需太多重复的TSQL。 结果如下:

A single index is returned against one of our index utilization tables. Never fear—I intentionally performed a ton of writes on the table to make this appear in our filters, but this illustrates how we can separate between unused indexes and underused indexes, allowing us to broaden the scope of analysis to include indexes that are used but might still be worth some scrutiny.

针对我们的索引利用率表之一返回单个索引。 不用担心-我故意在表上进行大量写操作以使它出现在我们的过滤器中,但这说明了如何区分未使用的索引和未充分使用的索引,从而使我们能够扩大分析范围,以包括已使用的索引,但也许仍然值得仔细研究。

The index returned above has only 1.2% of all operations as reads, meaning that we pay quite a bit for maintenance, and may not get a very good value for it. It’s possible those 1.2 % are extremely important, or perhaps they are not. These are the questions that we should consider prior to making any changes.

上面返回的索引仅占读取的所有操作的1.2%,这意味着我们为维护付出了很多,并且可能无法获得很好的价值。 这1.2%可能非常重要,或者可能并非如此。 这些是我们进行任何更改之前应考虑的问题。

Our last category of the index to consider is one that is ineffectively used. These would be indexes that are scanned frequently and rarely or never the target of seek operations. While it may be by design, I would be concerned if an index on a large/busy production table were being scanned often. If we are not intentionally looking to return a large portion (or all) of the index, then a great deal of reads is being wasted.

我们要考虑的索引的最后一类是使用无效的索引。 这些索引是经常扫描的索引,很少或永远不会是搜索操作的目标。 尽管可能是设计使然,但我会担心是否经常扫描大型/繁忙生产表上的索引。 如果我们不是故意要返回很大一部分(或全部)索引,那么大量的读取就被浪费了。

Similar to earlier, we will set an arbitrary break point for determining if an index is effective or not. If 98% or more of operations are scans, then we will flag it as a potential problem. We can use the following query to check for any indexes that happen to meet this criterion:

与前面类似,我们将设置一个任意断点来确定索引是否有效。 如果98%或更多的操作是扫描,那么我们会将其标记为潜在问题。 我们可以使用以下查询来检查碰巧符合此条件的所有索引:


WITH CTE_UNDERUSED_INDEXES AS (SELECT*,CAST(Index_Utilization_Summary.User_Seek_Count_Total + Index_Utilization_Summary.User_Scan_Count_Total + Index_Utilization_Summary.User_Lookup_Count_Total AS DECIMAL(19,2)) AS Read_CountFROM IndexMetrics.Index_Utilization_Summary  )
SELECTCTE_UNDERUSED_INDEXES.Index_Utilization_Summary_Create_Datetime,CTE_UNDERUSED_INDEXES.Index_Utilization_Summary_Last_Update_Datetime,CTE_UNDERUSED_INDEXES.Database_Name,CTE_UNDERUSED_INDEXES.[Schema_Name],CTE_UNDERUSED_INDEXES.Table_Name,CTE_UNDERUSED_INDEXES.Index_Name,CTE_UNDERUSED_INDEXES.User_Seek_Count_Total,CTE_UNDERUSED_INDEXES.User_Scan_Count_Total,CTE_UNDERUSED_INDEXES.User_Lookup_Count_Total,CTE_UNDERUSED_INDEXES.User_Update_Count_Total,CTE_UNDERUSED_INDEXES.Last_User_Seek,CTE_UNDERUSED_INDEXES.Last_User_Scan,CTE_UNDERUSED_INDEXES.Last_User_Lookup,CTE_UNDERUSED_INDEXES.Last_User_Update
FROM CTE_UNDERUSED_INDEXES
WHERE CTE_UNDERUSED_INDEXES.User_Scan_Count_Total / CASE WHEN CTE_UNDERUSED_INDEXES.Read_Count = 0 THEN 1 ELSE CTE_UNDERUSED_INDEXES.Read_Count END >= 0.98;

Reviewing the results, we can see that there are 9 indexes that happen to meet this criteria:

查看结果,我们发现有9个索引恰好满足此条件:

As we look at these indexes, it becomes clear that the solution may not be straightforward. Dropping these indexes is not going to solve our scan problems (if they are actually problematic). Some are clustered primary keys, which are important to our underlying data.

当我们查看这些索引时,很明显,解决方案可能并不简单。 删除这些索引并不能解决我们的扫描问题(如果它们确实有问题)。 一些是集群主键,对我们的基础数据很重要。

To investigate further, we’d want to check and see if these scans are a performance concern. If they are, then there are likely missing indexes that could address them or a known problem-query that could be responsible for them. In other words, this data is useful as it provides an additional metric when analyzing an overall indexing strategy. The correct action may be to do nothing, or it may involve further research. We may be able to use this data to corroborate other performance concerns in order to make a solid case in favor of other schema or application changes.

为了进一步调查,我们想检查一下这些扫描是否与性能有关。 如果是这样,则可能会缺少可以解决这些问题的索引,或者可能是对它们负责的已知问题查询。 换句话说,此数据很有用,因为它在分析整体索引策略时提供了额外的指标。 正确的措施可能是什么都不做,或者可能需要进一步的研究。 我们可能能够使用此数据来证实其他性能问题,从而为支持其他架构或应用程序更改提供可靠的理由。

缺少SQL Server索引分析 (Missing SQL Server Index Analysis)

Now that we have reviewed our existing indexes, we can begin to look at what indexes are missing and could benefit performance on a given database. As always, not all missing indexes are good indexes, so we need to evaluate each carefully before making any changes in a production environment. We can query our existing missing index data in order to determine which are important to us:

现在,我们已经检查了现有索引,我们可以开始查看缺少哪些索引,这些索引可以改善给定数据库的性能。 与往常一样,并非所有丢失的索引都是好的索引,因此我们需要在生产环境中进行任何更改之前仔细评估每个索引。 我们可以查询现有的缺失索引数据,以确定哪些对我们很重要:


SELECT'CREATE MISSING INDEX' AS Recommended_Action,v_Missing_Index_Summary.First_Index_Suggestion_Time AS Index_Metric_Creation_Datetime,v_Missing_Index_Summary.Last_User_Seek AS Last_Recommended_Datetime,v_Missing_Index_Summary.[Database_Name],v_Missing_Index_Summary.[Schema_Name],v_Missing_Index_Summary.Table_Name,'Index_' + CONVERT (VARCHAR, ROW_NUMBER() OVER (ORDER BY v_Missing_Index_Summary.Index_Creation_Statement)) + '_' + v_Missing_Index_Summary.Table_Name AS Index_Name,v_Missing_Index_Summary.Equality_Columns,v_Missing_Index_Summary.Inequality_Columns,v_Missing_Index_Summary.Include_Columns,v_Missing_Index_Summary.User_Seeks AS User_Seek_Count,NULL AS User_Scan_Count,NULL AS User_Lookup_Count,NULL AS User_Update_Count,NULL AS Last_User_Seek,NULL AS Last_User_Scan,NULL AS Last_User_Lookup,NULL AS Last_User_Update,NULL AS Is_Primary_Key,NULL AS Is_Clustered_Index,v_Missing_Index_Summary.Improvement_Measure,NULL AS Is_Unused,NULL AS Is_Dropped
FROM IndexMetrics.v_Missing_Index_Summary
WHERE v_Missing_Index_Summary.Improvement_Measure > 5

The filters on this query will ignore any missing index that has already been implemented but more importantly will only return missing indexes with an improvement measure greater than 5. This number is completely arbitrary and you are free to adjust up or down based on your sensitivity towards recommendations. Adjust it higher, get fewer results—adjust it lower and get more results.

此查询中的过滤器将忽略任何已实施的缺失索引,但更重要的是,只会返回改善程度大于5的缺失索引。此数字完全是任意的,您可以根据自己的敏感度随意向上或向下调整建议。 对其进行更高的调整,可获得更少的结果,而对其进行较低的调整,可获得更多的结果。

Here are the suggested missing indexes on my local SQL Server:

这是我的本地SQL Server上建议的缺少索引:

Included are all metrics on the missing index, including the number of benefitting seeks that would have occurred, as well as the improvement measure (off the right side of the screen). The index name is also completely arbitrary, but I find it useful to fill in the blank with something meaningful. It can easily be adjusted to fit whatever index naming convention you follow in order to make this more convenient.

其中包括遗失索引上的所有指标,包括可能发生的获利寻求的数量以及改进措施(位于屏幕右侧)。 索引名称也完全是任意的,但我发现用有意义的内容填充空白很有用。 可以轻松调整它以适应您遵循的任何索引命名约定,以使其更加方便。

一些SQL Server索引建议调整 (Some SQL Server Index Recommendation Tweaks)

Clustered indexes are special in that they form the logical basis for storage of a table. Unused clustered indexes strongly imply that the table as a whole is not used. More research is required—for example, to determine if all non-clustered indexes are also unused, but this scenario is worth noting:

聚集索引的特殊之处在于它们构成了存储表的逻辑基础。 未使用的聚集索引强烈暗示着整个表未使用。 需要做更多的研究,例如,确定是否还没有使用所有非聚集索引,但是这种情况值得注意:


SELECTIndex_Utilization_Summary.Database_Name,Index_Utilization_Summary.[Schema_Name],Index_Utilization_Summary.Table_Name,Index_Utilization_Summary.Index_Name,Index_Utilization_Summary.Index_Utilization_Summary_Create_Datetime,Index_Utilization_Summary.Index_Utilization_Summary_Last_Update_Datetime,Index_Utilization_Summary.User_Update_Count_Total,Index_Utilization_Summary.Last_User_Update,DATEDIFF(DAY, Index_Utilization_Summary.Index_Utilization_Summary_Create_Datetime, Index_Utilization_Summary.Index_Utilization_Summary_Last_Update_Datetime) AS Days_Without_Reads
FROM IndexMetrics.Index_Utilization_Summary
WHERE Index_Utilization_Summary.User_Seek_Count_Total = 0
AND Index_Utilization_Summary.User_Scan_Count_Total = 0
AND Index_Utilization_Summary.User_Lookup_Count_Total = 0
AND Index_Utilization_Summary.User_Update_Count_Total = 0
AND Index_Utilization_Summary.Is_Clustered_Index = 1;

This query is similar to our search for unused indexes, except that it also validates if it is a clustered index with absolutely no use at all (reads or writes). The results can allow us to ask the question: “Is this table unused?”. From that question, we can determine if it is unused, and if so, is this a good thing? Are all other non-clustered indexes on the table unused? If truly unused, can it be dropped? Unused tables can result from failed or nonexistent cleanup projects, but could also be a sign that an application is failing to use a table correctly.

该查询类似于我们对未使用索引的搜索,不同之处在于它还会验证它是否是完全没有使用(读或写)的聚集索引。 结果可以使我们提出一个问题:“此表是否未使用?”。 从这个问题,我们可以确定它是否未使用,如果是,这是件好事吗? 表上的所有其他非聚集索引是否未使用? 如果确实未使用,可以将其丢弃吗? 未使用的表可能是由于清理项目失败或不存在导致的,但也可能表示应用程序无法正确使用表。

An alternate way to view unused index data is to constrain usage by the last time the table was used. Perhaps it is not unused for all-time, but it has been unused in the past month. The following query will determine if any indexes have not received a read or write in the past month, but were not picked up by our unused index check from earlier:

查看未使用的索引数据的另一种方法是在上次使用该表之前限制使用情况。 也许它并非一直未被使用,但在过去一个月中一直未被使用。 以下查询将确定在过去一个月中是否没有任何索引接受过读取或写入,但是之前的未使用索引检查未将其选中:


SELECT*
FROM IndexMetrics.Index_Utilization_Summary
WHERE (Index_Utilization_Summary.Last_User_Seek IS NULL OR Index_Utilization_Summary.Last_User_Seek <= DATEADD(MONTH, -1, CURRENT_TIMESTAMP))
AND (Index_Utilization_Summary.Last_User_Scan IS NULL OR Index_Utilization_Summary.Last_User_Scan <= DATEADD(MONTH, -1, CURRENT_TIMESTAMP))
AND (Index_Utilization_Summary.Last_User_Lookup IS NULL OR Index_Utilization_Summary.Last_User_Lookup <= DATEADD(MONTH, -1, CURRENT_TIMESTAMP))
AND (Index_Utilization_Summary.Last_User_Update IS NULL OR Index_Utilization_Summary.Last_User_Update <= DATEADD(MONTH, -1, CURRENT_TIMESTAMP))
AND (Index_Utilization_Summary.Last_User_Seek + Index_Utilization_Summary.Last_User_Scan + Index_Utilization_Summary.Last_User_Lookup + Index_Utilization_Summary.Last_User_Update <> 0)

One final check we can make it to look for clustered index scans. Earlier, we identified misused indexes: Those with far more scans than seeks. When the index with a high scan count happens to be the clustered index, then we know that there may be some queries out there that are not covered by indexes but should be. We can filter and get info on these like this:

我们可以进行最后一项检查,以查找聚簇索引扫描。 之前,我们确定了误用的索引:扫描次数远多于查找次数的索引。 当具有较高扫描计数的索引恰好是聚集索引时,那么我们知道那里可能存在一些未被索引覆盖但应该包含的查询。 我们可以像这样过滤并获取有关信息:


WITH CTE_UNDERUSED_INDEXES AS (SELECT*,CAST(Index_Utilization_Summary.User_Seek_Count_Total + Index_Utilization_Summary.User_Scan_Count_Total + Index_Utilization_Summary.User_Lookup_Count_Total AS DECIMAL(19,2)) AS Read_CountFROM IndexMetrics.Index_Utilization_SummaryWHERE Index_Utilization_Summary.Is_Clustered_Index = 1   )
SELECTCTE_UNDERUSED_INDEXES.Index_Utilization_Summary_Create_Datetime,CTE_UNDERUSED_INDEXES.Index_Utilization_Summary_Last_Update_Datetime,CTE_UNDERUSED_INDEXES.Database_Name,CTE_UNDERUSED_INDEXES.[Schema_Name],CTE_UNDERUSED_INDEXES.Table_Name,CTE_UNDERUSED_INDEXES.Index_Name,CTE_UNDERUSED_INDEXES.User_Seek_Count_Total,CTE_UNDERUSED_INDEXES.User_Scan_Count_Total,CTE_UNDERUSED_INDEXES.User_Lookup_Count_Total,CTE_UNDERUSED_INDEXES.User_Update_Count_Total,CTE_UNDERUSED_INDEXES.Last_User_Seek,CTE_UNDERUSED_INDEXES.Last_User_Scan,CTE_UNDERUSED_INDEXES.Last_User_Lookup,CTE_UNDERUSED_INDEXES.Last_User_Update
FROM CTE_UNDERUSED_INDEXES
WHERE CTE_UNDERUSED_INDEXES.User_Scan_Count_Total / CASE WHEN CTE_UNDERUSED_INDEXES.Read_Count = 0 THEN 1 ELSE CTE_UNDERUSED_INDEXES.Read_Count END >= 0.98;

The results of this tell us where more research is required. Odds are very good that one of two scenarios apply to this situation:

结果告诉我们需要更多的研究。 两种情况之一适用于这种情况的可能性很好:

  1. There is a missing index on the table that is resulting in a large number of clustered index scans. 表上缺少索引,这导致大量聚集索引扫描。
  2. There are queries hitting the table that SELECT *, or return enough columns that no missing index would make sense for it. 有查询命中SELECT *的表,或者返回了足够多的列,没有丢失的索引对它有意义。

For either scenario, we have identified a potential performance problem and can address whether it is one that requires fixing or if it is indicative of normal behavior.

对于这两种情况,我们都确定了潜在的性能问题,可以解决是需要修复的问题还是表明其行为正常的问题。

追踪指数建议 (Tracking Index Recommendations)

With all of the data collected above, it would be beneficial to collect, store, and reference it as needed. We can run queries like those shown here whenever needed, but there will be some time savings if we turn the various queries into a stored procedure and were able to reference the collected data anytime.

使用上面收集的所有数据,根据需要收集,存储和引用它会很有用。 我们可以在需要时运行类似此处所示的查询,但是如果我们将各种查询转换为存储过程并能够随时引用所收集的数据,则会节省一些时间。

This process will collect the data above and then crunch it to determine if any previous recommendations were implemented. The goal is for the process to be as simple as possible:

此过程将收集上面的数据,然后对其进行处理,以确定是否实施了先前的任何建议。 目的是使过程尽可能简单:

  1. Collect index recommendations 收集索引建议
  2. Adjust for special cases, such as clustered index usage. 调整特殊情况,例如聚集索引的使用情况。
  3. Check for implementation status. 检查实施状态。
  4. Done! 做完了!

From that point, the data is available for review anytime. Attached to this article are updated versions of the missing index collection process, index utilization process, and a new process that will collect and analyze this data for you. This is optional but could be a nice way to codify how indexes should be managed, reducing the chance for mistaken decisions or inconsistent filters.

从那时起,可以随时查看数据。 本文附带的是缺少索引收集过程,索引使用过程以及将为您收集和分析此数据的新过程的更新版本。 这是可选的,但可能是一种很好的方式来整理应如何管理索引,从而减少了决策错误或过滤器不一致的机会。

The missing index and index utilization collection processes can be used independently of the recommendation proc successfully. They can be scheduled to run daily and allowed to collect data that can, over time, be used to make smart indexing decisions.

可以成功使用丢失的索引和索引利用率收集过程,而与推荐过程无关。 可以将它们安排为每天运行,并允许它们收集可随时间推移用于制定智能索引决策的数据。

关于复杂性的注释 (A Note on Complexity)

With any script that analyzes data and returns recommendations, there is the threat of building a black box so complex that it becomes uncertain how it works or why. Such a script also becomes error-prone and more likely to break under various unforeseen circumstances. Our goal in this effort is to develop insight into index metrics without going overboard.

使用任何分析数据并返回建议的脚本,都存在构建黑匣子的威胁,以至于无法确定黑匣子的工作方式或原因。 这样的脚本也容易出错,并且在各种不可预见的情况下更容易中断。 我们努力的目标是在不过度投入的情况下深入了解索引指标。

By persisting index data, we can generate very accurate data over time without the need for guesswork. In addition, we avoid the potential pitfall that arises if recommendations are given with too little historical data to build on. On the whole, the collection process requires 4 tables, 2 stored procedures, 2 views, and 2 jobs. The recommendation process requires a single stored procedure, table, and a calling job. The intention of this is to ensure that each object is short and sweet so that no component of this process becomes excessively complex.

通过持久保留索引数据,我们可以随时间生成非常准确的数据,而无需进行猜测。 此外,如果推荐的历史数据太少,我们将避免潜在的陷阱。 总体而言,收集过程需要4个表,2个存储过程,2个视图和2个作业。 推荐过程需要单个存储过程,表和调用作业。 这样做的目的是确保每个对象简短而甜美,以使该过程的任何组成部分都不会变得过于复杂。

If it helps, you may put all objects in this process into their own schema, segregating them from other objects and making them easy to find and work with. I used IndexMetrics for the demos here, but any can be used.

如果有帮助,您可以将此过程中的所有对象放入它们自己的模式中,将它们与其他对象隔离开来,使它们易于查找和使用。 我在这里的演示中使用了IndexMetrics ,但是任何都可以使用。

I am a huge proponent of understanding how SQL Server works and using that knowledge to make great decisions. At the same time, an attempt has been made here to keep things as simple as possible. Feel free to download, test, and use the attached scripts to make smart decisions. Once understood, these scripts can be built on and made bigger, badder, and more custom-tailored to your needs.

我强烈理解SQL Server的工作原理,并利用这些知识来做出明智的决定。 同时,这里尝试使事情尽可能简单。 随时下载,测试和使用附带的脚本来做出明智的决定。 一旦理解,就可以构建这些脚本,并使它们变得更大,更糟糕,并根据您的需求进行定制化。

With that in mind, please enjoy

索引sql server_SQL Server报告– SQL Server索引利用率相关推荐

  1. sql索引调优_使用内置索引利用率指标SQL Server索引性能调优

    sql索引调优 描述 (Description) Indexing is key to efficient query execution. Knowing what indexes are unne ...

  2. 索引sql server_SQL Server索引设计的五个主要注意事项

    索引sql server In this article, we will discuss the most important points that we should consider when ...

  3. 索引sql server_SQL Server索引操作

    索引sql server In the previous articles of this series, we described the structure of the SQL Server t ...

  4. 索引sql server_SQL Server索引–系列介绍

    索引sql server 描述 (Description) In this series, we will dive deeply in the SQL Server Indexing field, ...

  5. 索引sql server_SQL Server索引结构和概念

    索引sql server In my previous article, SQL Server Table Structure Overview, we described, in detail, t ...

  6. 索引sql server_SQL Server索引设计基础和准则

    索引sql server In the previous article of this series, SQL Server Index Structure and Concepts, we des ...

  7. SQL Server中的聚集索引与堆

    摘要 (Summary) There are few topics so widely misunderstood and that generates such frequent bad advic ...

  8. 【翻译】SQL Server索引进阶:第三级,聚集索引

    原文地址: Stairway to SQL Server Indexes: Level 3, Clustered Indexes 本文是SQL Server索引进阶系列(Stairway to SQL ...

  9. 【翻译】SQL Server索引进阶:第八级,唯一索引

    原文地址: Stairway to SQL Server Indexes: Level 8,Unique Indexes 本文是SQL Server索引进阶系列(Stairway to SQL Ser ...

最新文章

  1. c++迭代器模式iterator
  2. python模式选择符,Python设计模式之修饰器模式
  3. [ofbiz]less-than (lt;) and greater-than (gt;) symbols
  4. Java学习笔记(7)——输入输出
  5. SparkStreaming基础
  6. openGL与openGL ES 的区别
  7. C++_类和对象_对象特性_友元_成员函数做友元---C++语言工作笔记054
  8. 【1】mongoDB 的安装及启动
  9. IE 8 HTML Parsing Error:Unable to modify the parent container element before the child element is...
  10. Vue安装 devTool 时报错的解决办法
  11. 基于python的贪吃蛇游戏设计论文_《贪吃蛇游戏课程设计》报告毕业设计(论文)...
  12. Linux版MySQL下载教程
  13. (vue)h5 通过高德地图(原生) 获取当前位置定位
  14. npm i 安装插件报:permission denied, symlink
  15. 会议OA之我的会议(查询)
  16. 卡特兰数Catalan number的应用
  17. CultureInfo 类
  18. 表情包小程序,副业日入400+
  19. 打造自己的无人船(1)——树莓派环境搭建
  20. 121.Android 简单的人工智能聊天项目,chatAi,AI聊天项目,GPTAi

热门文章

  1. android 控件xpath软件_Appium-关于appium的原生控件的 xpath 定位问题及常用方法
  2. Windows Live Writer
  3. HttpsessionListener 实现在线人数统计
  4. HDU - 1043 Eight (A*搜索)
  5. SpringBoot项目如何进行打包部署
  6. 如何下载HLS视频到本地(m3u8)
  7. mongodb 监控分析命令
  8. MonoTouch 二三事(三)mono mkbundle 打包程序的解包支持
  9. JavaScript学习(二十六)—事件处理程序的添加与删除
  10. 5G是什么?5G能做什么?5G在未来将带来什么?