dataframe索引筛选

介绍 (Introduction)

Filtered indexes are well documented, as they have been around in SQL Server for almost six years now. Despite their longevity and usefulness, discussions of them tend to be very simple overviews using simple queries and not digging too deeply into more precise costs and benefits. This article is inspired by a production problem that cropped up recently involving a filtered index that illustrated that general knowledge of their function was not as complete as it should have been.

过滤索引已被很好地记录下来,因为它们已经在SQL Server中使用了近六年了。 尽管它们的长寿和实用性,但它们的讨论往往是使用简单查询的非常简单的概述,而不是深入研究更精确的成本和收益。 本文的灵感来自于最近出现的一个生产问题,该问题涉及一个经过筛选的索引,该索引表明对它们的功能的一般了解并不如应有的完整。

善良 (The Good)

The primary reason that we use filtered indexes is to address a query or set of queries that only requires a small portion of a table in order to return the data requested. This is common in tables where statuses exist that delineate active data from complete or archived data. It is also common when we have very narrow search terms that consistently address a very selective data set, such as orders that are not yet shipped, employees that are sick, or products that are out of stock. The following are a few common uses of filtered indexes. If you’re already familiar with how and why they are used, feel free to skip to the next section where we dig deeper into their hidden costs!

我们使用过滤索引的主要原因是为了解决一个查询或一组查询,这些查询只需要表的一小部分即可返回所请求的数据。 这在存在状态的表中很常见,这些状态将活动数据与完整或存档数据区分开来。 当我们的搜索字词非常狭窄且始终能够处理非常有选择性的数据集(例如尚未发货的订单,生病的员工或产品缺货)时,这也很常见。 以下是过滤索引的一些常见用法。 如果您已经熟悉如何使用它们以及为什么使用它们,请随时跳到下一部分,我们将在其中进一步探讨其隐藏成本!

These are the sorts of use cases that we would spend a great deal of time reporting on, but realize that in very large tables the cost of running these queries, even using covering indexes, can be significant. I have taken the sales order tables in AdventureWorks and have expanded them to be significantly larger, leaving Sales.SalesOrderHeader with about 1.3 million rows and Sales.SalesOrderDetail with about 5 million rows. For this makeshift example, we will add some new statuses to SalesOrderHeader:

这些是我们将花费大量时间报告的用例,但要意识到,在非常大的表中,即使使用覆盖索引,运行这些查询的成本也可能很高。 我已经在AdventureWorks中使用了销售订单表,并将它们扩展到更大,使Sales.SalesOrderHeader大约有130万行,而Sales.SalesOrderDetail大约有500万行。 对于这个临时示例,我们将向SalesOrderHeader添加一些新状态:

  1. Open (1000 rows set to this status)打开 (已将1000行设置为此状态)
  2. In Transit (500 rows set to this status)在途中 (此状态设置为500行)
  3. Shipped (750 rows set to this status)
  4. 已发货已将 750行设置为此状态)
  5. Canceled (100 rows set to this status)
  6. 已取消已将 100行设置为此状态)
  7. Complete (1,287,815 rows left in this status)已完成 (此状态还剩1,287,815行)

With this data set created, we want to focus on the data that would most likely interest the AdventureWorks Cycles Company in their OLTP system. This would primarily be the data for bicycle orders that are not yet completed, which represents a very small fragment of the total order count. Here is an example of a common query that may be used to pull data for use by the shipping department, who will only be interested in unshipped orders:

创建此数据集后,我们希望重点关注AdventureWorks Cycles Company在其OLTP系统中最可能感兴趣的数据。 这主要是尚未完成的自行车订单数据,仅占总订单数量的很小一部分。 这是一个常见查询的示例,可用于提取数据以供运输部门使用,运输部门仅对未装运的订单感兴趣:


SELECTSalesOrderHeader.SalesOrderID,SalesOrderHeader.DueDate,SalesOrderHeader.Status,SalesOrderHeader.AccountNumber,SalesOrderHeader.TotalDue
FROM Sales.SalesOrderHeader
WHERE Status = 1;

This returns some basic order data for all orders that have yet to be shipped. From here, the warehouse can put together the needed data in order to ship the order so it gets to its destination on time. The performance can be illustrated in the following execution plan:

这将为所有尚未发货的订单返回一些基本订单数据。 仓库可以从此处整理所需的数据,以运送订单,以便按时到达目的地。 可以在以下执行计划中说明性能:

Since there is no index on status, we need to use the clustered index in order to find the data we are looking for. The subtree cost for this 23.2308 and the STATISTICS IO are as follows:

由于没有关于状态的索引,因此我们需要使用聚簇索引才能找到我们要查找的数据。 此23.2308和STATISTICS IO的子树成本如下:

Table ‘SalesOrderHeader’. Scan count 5, logical reads 30310, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

表'SalesOrderHeader'。 扫描计数5,逻辑读30310,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。

In an effort to remove the expensive clustered index seek, we add an index on this table:

为了消除昂贵的聚集索引查找,我们在此表上添加了一个索引:


CREATE NONCLUSTERED INDEX IX_SalesOrderHeader_XL_status_covering ON Sales.SalesOrderHeader(Status)
INCLUDE(DueDate, AccountNumber, TotalDue);

After adding this index, our performance improves significantly. The subtree cost is 0.0092, and the execution plan is this:

添加此索引后,我们的性能将大大提高。 子树成本为0.0092,执行计划为:

Table ‘SalesOrderHeader’. Scan count 1, logical reads 11, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

表'SalesOrderHeader'。 扫描计数1,逻辑读11,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。

This query is run constantly, though, in order to locate the next order to package and ship. Despite the efficiency improvement, it still causes some contention and you’re asked to find an even faster alternative. A filtered index makes sense and you implement it as follows:

但是,此查询会不断运行,以便找到要打包和运送的下一个订单。 尽管效率有所提高,但仍会引起一些争用,您需要找到更快的替代方法。 筛选索引很有意义,您可以按以下方式实现它:


CREATE NONCLUSTERED INDEX IX_SalesOrderHeader_XL_status_filtered ON Sales.SalesOrderHeader(Status)
INCLUDE(DueDate, AccountNumber, TotalDue)
WHERE Status = 1;

Once added, performance improves even more, with a subtree cost of 0.0045, an execution plan that looks identical to the previous one (though using the filtered index):

一旦添加,性能将进一步提高,子树成本为0.0045,执行计划看起来与上一个相同(尽管使用过滤索引):

The STATISTICS IO shows a 9% reduction in reads:

统计IO显示读取减少了9%:

Table ‘SalesOrderHeader’. Scan count 1, logical reads 10, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

表'SalesOrderHeader'。 扫描计数1,逻辑读10,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。

Without some further design changes, our performance improvements stop here, but we have taken a problematic query and made it run very fast, even more so than the initial covering index allowed. The gains here may not seem huge, but if applied to a much larger table, can be invaluable. Let’s consider another example:

在没有进行进一步设计更改的情况下,我们的性能改进到此为止,但是我们进行了一个有问题的查询,并使其运行非常快,甚至超出了初始覆盖范围。 这里获得的收益似乎并不巨大,但是如果应用于更大的表中,则将是无价的。 让我们考虑另一个示例:


SELECTSalesOrderDetail.ProductID,SalesOrderDetail.SpecialOfferID,SalesOrderDetail.UnitPrice,SalesOrderDetail.UnitPriceDiscount,SalesOrderDetail.LineTotal,SalesOrderHeader.OrderDate,SalesOrderHeader.Status,SalesReason.Name
FROM Sales.SalesOrderDetail
INNER JOIN Sales.SalesOrderHeader
ON SalesOrderDetail.SalesOrderID = SalesOrderHeader.SalesOrderID
LEFT JOIN Sales.SalesOrderHeaderSalesReason
ON SalesOrderHeader.SalesOrderID = SalesOrderHeaderSalesReason.SalesOrderID
LEFT JOIN Sales.SalesReason
ON SalesReason.SalesReasonID = SalesOrderHeaderSalesReason.SalesReasonID
WHERE SpecialOfferID = 5
AND UnitPrice = 17.0955;

This query specifically looks for a small set of orders in which there is a specific offer and discount that is being applied. In order to cover this query, which is presumably run very often, we add the following index:

该查询专门查找一小组订单,其中有特定的报价和折扣正在应用。 为了涵盖此查询(它可能经常运行),我们添加了以下索引:


CREATE NONCLUSTERED INDEX IX_SalesOrderDetail_XL_SpecialOfferID_covering ON Sales.SalesOrderDetail(SpecialOfferID, UnitPrice)
INCLUDE(ProductID, UnitPriceDiscount, LineTotal);

Once added, we can review the execution plan, STATISTICS IO, and also the STATISTICS TIME output:

添加后,我们可以查看执行计划,STATISTICS IO以及STATISTICS TIME输出:

Table ‘SalesReason’. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘SalesOrderHeaderSalesReason’. Scan count 41, logical reads 82, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘SalesOrderHeader’. Scan count 0, logical reads 123, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘Worktable’. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘SalesOrderDetail’. Scan count 1, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

表“ SalesReason”。 扫描计数0,逻辑读0,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。
表'SalesOrderHeaderSalesReason'。 扫描计数41,逻辑读82,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。
表'SalesOrderHeader'。 扫描计数为0,逻辑读取为123,物理读取为0,预读为0,lob逻辑读取为0,lob物理读取为0,lob提前读取为0。
表“工作表”。 扫描计数0,逻辑读0,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。
表“ SalesOrderDetail”。 扫描计数1,逻辑读为4,物理读为0,预读为0,lob逻辑读为0,lob物理读为0,lob预读为0。

SQL Server Execution Times:
    CPU time = 0 ms, elapsed time = 106 ms.

SQL Server执行时间:
CPU时间= 0毫秒,经过的时间= 106毫秒。

The subtree cost for this execution is 0.0132. Now, let’s add a filtered index to SalesOrderDetail in order to better cover this query:

此执行的子树成本为0.0132。 现在,让我们向SalesOrderDetail添加一个过滤索引,以更好地覆盖此查询:


CREATE NONCLUSTERED INDEX IX_SalesOrderDetail_XL_SpecialOfferID_filtered ON Sales.SalesOrderDetail(SpecialOfferID, UnitPrice)
INCLUDE(ProductID, UnitPriceDiscount, LineTotal)
WHERE SpecialOfferID = 5 AND UnitPrice = 17.0955;

After running this, the performance metrics now look like this:

运行此命令后,性能指标现在如下所示:

Table ‘SalesReason’. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘SalesOrderHeaderSalesReason’. Scan count 41, logical reads 82, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘SalesOrderHeader’. Scan count 0, logical reads 123, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘Worktable’. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘SalesOrderDetail’. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

表“ SalesReason”。 扫描计数0,逻辑读0,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。
表'SalesOrderHeaderSalesReason'。 扫描计数41,逻辑读82,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。
表'SalesOrderHeader'。 扫描计数为0,逻辑读取为123,物理读取为0,预读为0,lob逻辑读取为0,lob物理读取为0,lob提前读取为0。
表“工作表”。 扫描计数0,逻辑读0,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。
表“ SalesOrderDetail”。 扫描计数1,逻辑读2,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。

SQL Server Execution Times:
    CPU time = 0 ms, elapsed time = 40 ms.

SQL Server执行时间:
CPU时间= 0 毫秒 ,经过 时间= 40 毫秒。

This time, the execution plan looks the same, and the reads are similar, though a bit lower. The runtime, though, is consistently less. In addition, the new index is smaller than the previous one. Here are the storage stats for the covering index with no filter applied:

这次,执行计划看起来相同,读取次数也相似,尽管要低一些。 但是,运行时间始终较少。 此外,新索引比以前的索引小。 以下是未应用过滤器的覆盖率指标的存储状态:

These are the storage stats for the filtered index:

这些是过滤索引的存储状态:

The unfiltered index takes up over 250MB of space, whereas the filtered index fits entirely on a single page! This not only saves valuable disk space, but reduces the time and resources consumed by index defragmentation processes.

未过滤的索引占用了250MB以上的空间,而过滤的索引则完全适合单个页面! 这不仅节省了宝贵的磁盘空间,而且减少了索引碎片整理过程所消耗的时间和资源。

We could build larger test tables to show more dramatic improvements, but there is more to tackle here than to show off what filtered indexes can do.

我们可以构建更大的测试表以显示更多显着的改进,但是除了展示过滤索引可以做什么之外,还有更多需要解决的问题。

筛选索引的成本 (The Cost of Filtered Indexes)

Whereas the benefits provided by all indexes are to improve read performance on specific columns or sets of columns for important queries, the cost paid for this is in write performance. With standard indexes, whenever a write operation is performed that happens to change columns included in an index, additional write operations need to be completed in order to update the index. As long as we properly maintain our indexes and don’t allow the number of them to get out of control, the read-write tradeoff we accept for those indexes is likely an excellent deal for us.

尽管所有索引提供的好处是可以改善重要查询的特定列或一组列的读取性能,但为此付出的代价是写入性能。 对于标准索引,只要执行写操作碰巧更改了索引中包含的列,就需要完成其他写操作才能更新索引。 只要我们适当地维护我们的索引并且不允许它们的数量失控,我们接受这些索引的读写权衡对我们来说可能就是一个很好的选择。

Filtered indexes contain additional metadata in the form of a WHERE clause, which can reference one or many columns, as illustrated in our previous examples. In addition to updating any sorting or include columns, the columns in the WHERE clause also participate in write operations when needed. This additional cost, when not accounted for, can result in unexpected latency or contention as SQL Server needs to check additional data values before updating the filtered index.

过滤后的索引包含WHERE子句形式的其他元数据,可以引用一个或多个列,如前面的示例所示。 除了更新任何排序或包含列之外,WHERE子句中的列还可以在需要时参与写操作。 如果不考虑这笔额外费用,则可能会导致意外的延迟或争用,因为SQL Server需要在更新过滤索引之前检查其他数据值。

Let’s reconsider the second index we created above:

让我们重新考虑我们在上面创建的第二个索引:

 CREATE NONCLUSTERED INDEX IX_SalesOrderDetail_XL_SpecialOfferID_filtered ON Sales.SalesOrderDetail(SpecialOfferID, UnitPrice)
INCLUDE(ProductID, UnitPriceDiscount, LineTotal)
WHERE SpecialOfferID = 5 AND UnitPrice = 17.0955;

This index covers an important query by sorting on two columns, including three, and filtering on the same pair that were sorted on. A typical index update can be triggered with any write operation such as this:

该索引通过对两列(包括三列)进行排序,并对已排序的同一对进行筛选,从而涵盖了重要的查询。 典型的索引更新可以通过任何写操作来触发,例如:


UPDATE Sales.SalesOrderDetailSET UnitPriceDiscount = 0.15
WHERE SalesOrderID = 50270
AND SalesOrderDetailID = 32300;

This represents a fairly common update scenario, where we intend to update a single row based on the primary key values. The resulting execution plan shows the effort needed to accomplish this:

这代表了一个相当普遍的更新方案,在该方案中,我们打算基于主键值来更新一行。 产生的执行计划显示了完成此任务所需的工作:

This shows the update of the clustered index, as well as the filtered index. The reads needed to complete this operation are relatively low:

这显示了聚集索引以及过滤索引的更新。 完成此操作所需的读取值相对较低:

Table ‘SalesOrderDetail’. Scan count 0, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

表“ SalesOrderDetail”。 扫描计数为0,逻辑读取为3,物理读取为0,预读为0,lob逻辑读取为0,lob物理读取为0,lob提前读取为0。

Let’s try another example that will illustrate results that are not quite as expected. To begin, we’ll drop the filtered index created above:

让我们尝试另一个示例,该示例将说明与预期不完全相同的结果。 首先,我们将删除上面创建的过滤索引:

 DROP INDEX IX_SalesOrderDetail_XL_SpecialOfferID_filtered ON Sales.SalesOrderDetail;

With the index gone, we’ll run a simple query against an existing index on this table:

索引消失后,我们将对该表上的现有索引运行一个简单查询:


UPDATE Sales.SalesOrderDetailSET UnitPriceDiscount = 0.15
WHERE ProductID = 776;

This is a simple update using an existing nonclustered index on ProductID in order to change the UnitPriceDiscount. The execution plan for it is, as above, the expected result:

这是一个简单的更新,它使用ProductID上的现有非聚集索引来更改UnitPriceDiscount 。 如上所述,它的执行计划是预期的结果:

The reads may seem high, but we are updating 9,348 rows in order to complete this statement:

读取次数似乎很高,但是为了完成以下语句,我们正在更新9,348行:

Table ‘SalesOrderDetail‘. Scan count 1, logical reads 28673, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

表' SalesOrderDetail '。 扫描计数1,逻辑读28673,物理读0,预读0,lob逻辑读0,lob物理读0,lob 预读0。

Now let’s put the filtered index back into place:

现在让我们将过滤后的索引放回原处:


CREATE NONCLUSTERED INDEX IX_SalesOrderDetail_XL_SpecialOfferID_filtered ON Sales.SalesOrderDetail(SpecialOfferID, UnitPrice)
INCLUDE(ProductID, UnitPriceDiscount, LineTotal)
WHERE SpecialOfferID = 5 AND UnitPrice = 17.0955;

When we run the same update statement from above, things get much more complicated:

当我们从上方运行相同的update语句时,事情变得更加复杂:

An expensive key lookup has appeared in what was once an innocuous execution plan. IO on this operation, as expected, is also much higher:

昂贵的密钥查找已经出现在曾经是无害的执行计划中。 如预期的那样,此操作的IO也更高:

Table ‘SalesOrderDetail’. Scan count 1, logical reads 56717, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘Worktable’. Scan count 1, logical reads 18926, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

表“ SalesOrderDetail”。 扫描计数1,逻辑读56717,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。
表“工作表”。 扫描计数1,逻辑读18926,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。

In addition to updating the clustered index on 9,348 rows, as we did above, we also performed an update on the filtered index as well. This additional update occurred, despite the fact that no rows in the result set matched the filter criteria for the filtered index. In other words, SQL Server had to verify the WHERE clause on the filtered index prior to determining if any updates had to be made, regardless of whether or not any rows were returned. This occurs because UnitPriceDiscount is in the include column list. A filtered index does not work in reverse: It is necessary to verify columns in the WHERE clause, even if no updates are required. The cost to perform this additional work was far from trivial, and if this query were run often, it could be crippling to a busy server.

除了像上面所做的那样在9,348行上更新聚簇索引之外,我们还对过滤后的索引进行了更新。 尽管结果集中没有行与过滤索引的过滤条件匹配,但还是发生了此附加更新。 换句话说,无论是否返回任何行,SQL Server都必须在确定是否必须进行任何更新之前验证筛选索引上的WHERE子句。 发生这种情况是因为UnitPriceDiscount在包含列列表中。 过滤后的索引不能反向工作:即使没有更新,也必须验证WHERE子句中的列。 执行这项额外工作的成本绝非易事,如果经常运行此查询,可能会使繁忙的服务器瘫痪。

Let’s run through a somewhat different example, this time on a query that does not update any columns that are included in the filtered index:

让我们来看一个稍微不同的示例,这一次是针对不更新过滤索引中包含的任何列的查询:


UPDATE Sales.SalesOrderDetailSET OrderQty = 0
WHERE ProductID = 776;

We are still targeting the index on ProductID with the WHERE clause, but are updating a different column that is not included in any indexes on Sales.SalesOrderDetail. Reviewing the execution plan and reads, though, reveals similar results to before:

我们仍然使用WHERE子句定位ProductID上的索引,但是正在更新Sales.SalesOrderDetail的任何索引中未包含的其他列。 回顾执行计划并阅读,会发现与以前类似的结果:

Table ‘SalesOrderDetail’. Scan count 1, logical reads 56717, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘Worktable’. Scan count 1, logical reads 18884, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

表“ SalesOrderDetail”。 扫描计数1,逻辑读56717,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。
表“工作表”。 扫描计数1,逻辑读18884,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。

In fact, everything looks exactly the same as it was before! Despite our not updating a column involved in the index at all, SQL Server still went through the trouble of checking the WHERE clause anyway. If we remove the index, the execution plan and IO return to what we would expect of this query:

实际上,一切看起来都和以前一样! 尽管我们根本没有更新索引中涉及的列,但是SQL Server仍然遇到了检查WHERE子句的麻烦。 如果删除索引,执行计划和IO将返回我们对该查询的期望:

Table ‘SalesOrderDetail’. Scan count 1, logical reads 28673, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

表“ SalesOrderDetail”。 扫描计数1,逻辑读28673,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。

结论 (Conclusion)

The effects of adding a filtered index were far more significant than would be expected for some of the queries presented above. It may be easy for a DBA to forget that a filtered index would influence any other queries that update data within it. The fact that unrelated queries still caused unnecessary reads in order to essentially complete a no-op is not something anyone would assume.

添加过滤索引的影响远比上面介绍的某些查询所预期的要重要得多。 DBA可能很容易忘记过滤索引会影响更新其中数据的其他任何查询。 不相关的查询仍会引起不必要的读取以基本完成无操作这一事实,这并不是任何人都会想到的。

Based on these experiences, I am now much more cautious towards filtered indexes. In any scenario where I would consider them, I would feel obliged to do research into common write operations on the table to ensure they won’t be adversely affected by the new index. Regardless of whether the write operations affect columns within a filtered index, we would want to be vigilant anyway to ensure that we are not being harmed either by carelessness or unexpected behavior.

基于这些经验,我现在对过滤索引更加谨慎。 在我考虑使用它们的任何情况下,我都必须对表上的常见写操作进行研究,以确保它们不会受到新索引的不利影响。 无论写操作是否影响筛选索引中的列,我们都希望保持警惕,以确保我们不会因粗心或意外行为而受到伤害。

Microsoft has a Connect article that addresses this bug, submitted by Paul White.

Microsoft有一篇由Paul White提交的针对此错误的Connect文章 。

It is unclear if this issue will be addressed in the future. My hope is that Microsoft will take a feature that appeared to be a cure-all for queries on large tables and improve it so that we aren’t sideswiped by unexpected performance problems.

尚不清楚将来是否会解决此问题。 我希望微软能够采取一项似乎可以解决所有大表查询问题的功能并对其进行改进,以使我们不会因意料之外的性能问题而sides不休。

翻译自: https://www.sqlshack.com/filtered-indexes-performance-analysis-and-hidden-costs/

dataframe索引筛选

dataframe索引筛选_筛选的索引:性能分析和隐藏成本相关推荐

  1. mysql的覆盖索引原理_「Mysql索引原理(七)」覆盖索引

    通常大家都会根据查询的WHERE条件来创建合适的索引,不过这只是索引优化的一个方面.设计优秀的索引应该考虑到整个查询,而不单单是WHERE条件部分.索引确实是一种查找数据的高效方式,但是MySQL也可 ...

  2. sql server 创建唯一性非聚集索引语句_数据库专题—索引原理

    深入浅出数据库索引原理 参见:https://www.cnblogs.com/aspwebchh/p/6652855.html 1.为什么给表加上主键? 1.平时创建表的时候,都会给表加上主键.如果没 ...

  3. mysql group 索引失效_介绍mysql索引失效的情况

    mysql视频教程栏目索引失效的情况. 索引对于MySQL而言,是非常重要的篇章.索引知识点也巨多,要想掌握透彻,需要逐个知识点一一击破,今天来先来聊聊哪些情况下会导致索引失效. 图片总结版 相关免费 ...

  4. mysql设置索引长度_修改Mysql索引长度限制

    mysql 索引过长1071-max key length is 767 byte 问题 create table: Specified key was too long; max key lengt ...

  5. mysql or走索引吗_加了索引,mysql查询就一定会用吗?

    小白白跑去鹅厂面试,面试官提出了一个很实际的问题: mysql增加索引,那些情况会失效呢?谈一下实际工作中遇到的情况.我们的小白白又抛出了白氏秘籍:用不用索引,找DBA小姐姐!啊?这是你面试哈,还是D ...

  6. Mysql 唯一索引长度_关于mysql索引长度的相关内容总结

    MySQL优化之-索引具体代码分析:索引是在存储引擎中实现的,因此每种存储引擎的索引都不一定完全相同,并且每种存储引擎也不一定支持所有索引类型.根据存储引擎定义每个表的最大索引数和最大索引长度.所有存 ...

  7. 冒泡和快速排序的时间复杂度_八大排序算法性能分析及总结

    一.排序算法说明 排序的定义:对一个无序的序列进行排序的过程. 输入:n个数:a1,a2,a3,-,an. 输出:n个数的排列:a1,a2,a3,-,an,使得a1<=a2<=a3< ...

  8. 当电压放大电路的开路增益和输出电阻固定后_晶体管放大电路的性能分析与应用...

    关于三极管共射极放大电路的基本分析方法(见附录1),我们之前有聊过.本文重点与大家分享下电路的性能分析,尤其电路的频率响应与选频特性,还是非常有趣的.主要内容有: 输入输出电阻 通频带 如何提高放大倍 ...

  9. mysql 性能分析_十大MySQL性能分析工具汇总!专治MySQL性能瓶颈

    前言 MySQL 数据库最常见的两个瓶颈是CPU和I/O的瓶颈.CPU在饱和的时候一般发生在数据装入内存或从磁盘上读取数据时候,磁盘I/O瓶颈发生在装入数据远大于内存容量的时候. MySQL数据库性能 ...

最新文章

  1. 如何为网站增加索引,促进网站SEO优化?
  2. 【OpenCV入门指南】第五篇 轮廓检测 上
  3. Android Log等级的介绍
  4. 推荐干货 | 我在阿里做运营:八一八运营经典误区
  5. Graphpad Prism 9绘制子列图与柱状图
  6. TCP连接(client、server)状态转换
  7. 简化从Win32到Windows 10的迁移之路
  8. java类什么时候卸载_java – Android:什么时候类被系统卸载?
  9. php 随机在文章中添加锚文本_锚文本对网站SEO优化有什么帮助?
  10. Tomcat服务器 Servlet
  11. php+apache 和 php+nginx的区别
  12. arm linux tcp,ARM Linux多连接TCP服务器的应用程序设计
  13. 优雅的实现对外接口,要注意哪些问题?
  14. linux规定ip使用网卡,使用TC 对LINUX服务器网卡进行带宽限制的办法
  15. 微软云架构服务器,微软云存储架构(Azure Cloud Storage)
  16. 在计算机应用领域中媒体是指,在计算机中,媒体是指什么
  17. 科研必备 | 谷歌学术高级搜索详解
  18. 利用E4A编写APP获取安卓手机加速度传感器数据
  19. 福禄克LinkIQ™智能链路通线缆网络测试仪功能介绍
  20. python爬虫练习高清壁纸【王者荣耀高清壁纸】python爬虫

热门文章

  1. 北信源管理网页卸载密码_怎么卸载找不到程序的流氓软件?
  2. Java笔记(十七) 异步任务执行服务
  3. 《http权威指南》读书笔记14
  4. [Luogu] 模板题-最近公共祖先
  5. bzoj1012: [JSOI2008]最大数maxnumber [单调队列]
  6. 单片机第13课:串口通信---向计算机发送数据
  7. RN style使用以及常用样式总结
  8. LeetCode(575)——分糖果(JavaScript)
  9. LeetCode(999)——车的可用捕获量(JavaScript)
  10. 零基础带你学习MySQL—primary key主键(二十三)