【问题标题】:Adding non-clustered index to a table to increase performance向表中添加非聚集索引以提高性能
【发布时间】:2017-03-06 00:14:41
【问题描述】:

我的表结构如下

CREATE TABLE [dbo].[AIRQUALITYTS2]
(
    [FeatureID] [nvarchar](20) NOT NULL,
    [ParameterID] [nvarchar](20) NOT NULL,
    [MeasurementDateTime] [datetime2](7) NOT NULL,
    [ParameterValue] [numeric](38, 8) NULL,
    [Remarks] [nvarchar](150) NULL,

    CONSTRAINT [PK_AIRQUALITYTS2] 
        PRIMARY KEY CLUSTERED ([FeatureID] ASC, [ParameterID] ASC, [MeasurementDateTime] ASC)
                    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                          IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                          ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

当我执行这个查询时:

set statistics io on

SELECT 
    COUNT(featureid), featureid 
FROM
    AIRQUALITYTS2 
WHERE
    FeatureID LIKE 'AS%' 
    AND ParameterID = 'AP2' 
    AND YEAR(MeasurementDateTime) = 2015
GROUP BY 
    FeatureID
ORDER BY 
    FeatureID

我看到逻辑记录101871,查询执行计划是

但是当我在这个表上添加非聚集索引时

 CREATE NONCLUSTERED INDEX non_fidpidmdate
     ON [dbo].[AIRQUALITYTS2] ([ParameterID], [FeatureID])
     INCLUDE ([MeasurementDateTime])

当我执行相同的查询时,我看到逻辑记录只读取 4636 并且速度非常快,查询执行计划是

问题1:当第二个查询中的逻辑记录较少时。

问题 2:为什么第一个查询使用 聚集索引扫描,如第一张图像中所示,尽管它在 featureid、ParameterID 和 MeasurementDateTime 上有聚集索引,而在添加非聚集索引后它使用 Index寻找(非集群)图片中显示的第二张图片

注意:我已将 where 子句更改为

MeasurementDateTime >= '2004-01-01 00:00:00' 
and MeasurementDateTime <= '2004-12-31 00:00:00' 

使其可搜索,但结果仍然相同。

【问题讨论】:

    标签: sql-server sql-execution-plan non-clustered-index


    【解决方案1】:

    对于问题 1:由于您的索引是覆盖(它包含查询要检索的所有数据,以及查询和排序所需的数据),因此可以完全针对索引运行查询(并且它的数据页)并使用 seek,这显然比扫描整个表(聚集索引扫描 =表扫描)时从磁盘加载的页面要少得多。数据。

    不确定你的问题 #2 是什么意思 ....

    【讨论】:

    • 在添加非集群索引之前,它使用集群索引扫描,而在它使用索引查找(非集群)之后
    • @user641812:是的 - 和?那有什么问题/问题/问题?我不明白你在期待什么,以及你看到的是什么——我看不出期望和现实之间有任何“差异”......
    • 感谢您的回复。那么我认为我需要更清楚地了解聚集索引和非聚集索引的工作原理。如果首先我们有种子然后在第二我们应该有相同的东西,我期待相同的行为。但是,如果你能帮我做同样的逻辑。还有在第一种情况下,我们如何对索引运行查询
    • 嗯,聚集索引的特殊之处在于它对表中的数据进行物理排序(这就是每个表只能有 1 个聚集索引的原因),而 叶节点是组成表的数据页 - 与任何其他索引不同。 SQL Server 查询优化器非常聪明地知道何时使用 seek,以及何时使用没有任何好处(选择使用 scan 代替)
    • 我们能否在第一种情况下针对索引运行查询。
    【解决方案2】:
    1. 在您创建PRIMARY KEY CLUSTERED 的原始CREATE TABLE 中,它指定要聚集的列,按照它们聚集(存储)的顺序
    [FeatureID]
    [ParameterID]
    [MeasurementDateTime]
    

    如果您使用包含特定FeatureIDWHERE 子句运行查询,那么它将能够seek 到索引的该部分。

    但是您还没有在查询中这样做。 你用过WHERE FeatureID LIKE 'AS%' ...

    查询引擎无法搜索,因为带有尾随通配符 %LIKE 意味着它必须扫描所有以字母 AS 开头的 FeatureID,然后在树中的每个节点中查看是否有匹配ParameterID = 'AP2' AND YEAR(MeasurementDateTime) = 2015的记录。

    1. 在您的非聚集索引中,您使用了不同的列顺序:
    [ParameterID]
    [FeatureID]
    

    当您运行相同的查询时,它可以seek,因为您在WHERE 子句中指定了一个精确的ParameterID

    订购很重要! SQL 索引是sortof B-Tree 数据结构,如果不创建多个索引,就无法以不同的顺序物理存储(或遍历它们)它们。创建太多索引可能会给数据库带来太多开销,所以是的,创建有助于大多数查询的索引,但不要创建太多。大多数情况下,这涉及了解经常针对您的数据库运行哪种查询并相应地进行调整。

    【讨论】:

      猜你喜欢
      • 2023-03-23
      • 2012-04-30
      • 2015-02-24
      • 1970-01-01
      • 1970-01-01
      • 2015-11-17
      • 1970-01-01
      • 1970-01-01
      • 2011-10-12
      相关资源
      最近更新 更多