【问题标题】:Sort Operation with Covering Index具有覆盖索引的排序操作
【发布时间】:2022-01-03 15:23:28
【问题描述】:

我们有一个查询在计划中产生一个排序操作,但我们有一个覆盖索引:

我的印象是覆盖索引将有助于减少对排序操作的需求。

查询计划: https://www.brentozar.com/pastetheplan/?id=By-AXqg2K

POSTAL_CODE 表:

CREATE TABLE [dbo].[POSTAL_CODE](
    [PC_VALUE] [nvarchar](6) NOT NULL,
    [PC_CITY] [nvarchar](50) NULL,
    [PC_SP_ABBREV] [nvarchar](3) NULL,
    [PC_COU_ABBREV] [nvarchar](2) NOT NULL,
    [PC_LATITUDE] [real] NULL,
    [PC_LONGITUDE] [real] NULL,
    [PC_TZ_ID] [int] NULL,
    [PC_OBSERVES_DAYLIGHT] [nchar](1) NULL,
    [PC_COUNTY] [nvarchar](50) NULL,
    [PC_DATE_INSERTED] [datetime] NOT NULL,
    [PC_DATE_UPDATED] [datetime] NOT NULL,
    [PC_STATUS] [nchar](1) NOT NULL,
    [PC_ZON_ID] [int] NULL,
    [PC_AREA_CODE] [nvarchar](3) NULL,
    [PC_PREFERRED] [nchar](1) NOT NULL,
    [PC_CLU_ID] [int] NULL,
    [PC_WORK_INDEX] [tinyint] NULL,
    [PC_WORK_MINS_DIFF] [smallint] NULL,
    [PC_LIS_COUNT] [smallint] NULL,
    [PC_WORK_MINS_AVG] [smallint] NULL,
 CONSTRAINT [POSTAL_CODE_POSTAL_CODE$PrimaryKey] PRIMARY KEY CLUSTERED 
(
    [PC_VALUE] ASC,
    [PC_COU_ABBREV] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]
) ON [PRIMARY]
GO

【问题讨论】:

  • 只有在任何搜索谓词之后的索引顺序与您对ORDER BY 请求的顺序相同时,覆盖索引才有助于避免排序 - ORDER BY ((3958 * 3.1415926 * SQRT((PC_LATITUDE - 1) * (PC_LATITUDE - 1) + COS(PC_LATITUDE / 57.29578) * COS(1 / 57.29578) * (PC_LONGITUDE - 1) * (PC_LONGITUDE - 1)) / 180)) ASC 不会出现这种情况
  • 您的查询是按表达式结果排序的,而不是直接按列排序。此设计需要进行全面扫描和分类。
  • 很难阅读您的查询,但我看到 PC_LATITUDE 出现在对 SQRT() 的函数调用中,因此我不确定您的索引是否会在这里使用。
  • 该索引对优化器没有用(用于排序),它在一开始就在PC_Value 上排序,但排序标准是值的函数,不能以同样的方式进行搜索一个 where 标准不会是 sargable。
  • 所以您可能想查看STDistance 和空间索引。虽然我自己也没有使用过这些。看起来相关docs.microsoft.com/en-us/sql/relational-databases/spatial/…

标签: sql-server


【解决方案1】:

服务器无法为您的查询使用此索引,因为排序标准是一个复杂的计算,这意味着结果不会与PC_VALUE 的排序顺序相同。

一种选择是在该计算上创建一个计算列,然后对其进行索引

ALTER TABLE POSTAL_CODE
  ADD Distance AS (
    3958 *
    3.1415926 *
    SQRT(
        (PC_LATITUDE - 1) * (PC_LATITUDE - 1) +
        COS(PC_LATITUDE / 57.29578) *
        COS(1 / 57.29578) *
        (PC_LONGITUDE - 1) * (PC_LONGITUDE - 1)
    ) /
    180)
  PERSISTED;  -- must be persisted because it is an imprecise (float) value
    
CREATE NONCLUSTERED INDEX IX ON POSTAL_CODE(Distance) INCLUDE (PC_VALUE);

现在你不会得到任何排序,如in this fiddle 所示。服务器可以简单地查看查询并说“我们已经为此值建立了索引,让我们查找索引中的第一行”。

您现在显然也可以仅引用该计算列:

SELECT TOP 1
  PC_VALUE
FROM POSTAL_CODE PC
ORDER BY Distance;

但我同意评论者的观点,您可能应该考虑使用geography 和空间索引。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-19
    相关资源
    最近更新 更多