SQL Server - 子查询中分组依据的索引效率

标签 sql sql-server indexing

尝试创建对此设置最有效的索引:

查看 (RANKED_PHONE):

SELECT PHONE_ID,
       CONTACT_ID,
       TYPE_CD,
       ROW_NUMBER() OVER( PARTITION BY CONTACT_ID, TYPE_CD 
                              ORDER BY UPDATE_DT DESC ) AS PHONE_RANK
FROM   (SELECT PHONE_ID,
               CONTACT_ID,
               TYPE_CD,
               UPDATE_DT
        FROM   contact_phone
        WHERE  PHONE_ID IN (SELECT MAX(PHONE_ID)
                            FROM   contact_phone WITH(NOLOCK)
                            GROUP  BY CONTACT_ID,
                                      TYPE_CD,
                                      PHONE_NUMBER)) nodupes 

当前指数:

CREATE CLUSTERED INDEX [CIX_contactphone_PHONEID]
  ON [contact_phone] ([PHONE_ID])
GO

CREATE NONCLUSTERED INDEX [NIX_contactphone_UPDATEDT]
  ON [contact_phone] ([UPDATE_DT])
GO

CREATE NONCLUSTERED INDEX [NIX_contactphone_CONTACTID_TYPECD_PHONENUMBER]
  ON [contact_phone] ([CONTACT_ID], [TYPE_CD], [PHONE_NUMBER])
GO 

其他说明:

  • 有一个 SSIS 包可以在 PHONE_ID 上运行查找来检查 是否插入或更新
  • 此 View 将进一步过滤 通过查找特定的 CONTACT_ID 并过滤掉 PHONE_ID 来进行选择 已被使用过。

编辑:我不妨包括我正在做的其余部分,这样您就可以看到最终图片:

SELECT @phone1 = COALESCE(CELL1, PERS1, BUS1, OTHER1, FAX1)
FROM(SELECT CELL1 = MAX(CASE WHEN PHONE_RANK = 1 THEN CELL END)
        , PERS1 = MAX(CASE WHEN PHONE_RANK = 1 THEN PERS END)
        , BUS1 = MAX(CASE WHEN PHONE_RANK = 1 THEN BUS END)
        , OTHER1 = MAX(CASE WHEN PHONE_RANK = 1 THEN OTHER END)
        , FAX1 = MAX(CASE WHEN PHONE_RANK = 1 THEN FAX END)
    FROM(
        SELECT * FROM [RANKED_PHONE]
        WHERE CONTACT_ID = @key
    ) phone
    PIVOT(MAX(PHONE_ID) 
        FOR TYPE_CD IN ([CELL],[PERS],[BUS],[OTHER],[FAX])
    ) as pvt) phones

选择@phone1后,“AND PHONE_ID NOT IN (@phone1)”被添加到从RANKED_PHONE中选择的where子句中,然后添加phone2..等等。这个查询的要点是填充一组根据业务规则,电话号码字段按一定的选择顺序排列。我想放入一个 View 以尽可能多地缓存它。由于我需要过滤掉已使用的电话号码,因此我无法将数据透视放入 View 中,因为它们需要在旋转之前进行过滤。

* 主要编辑 *

这里发生了一些变化:

  • 因为我在后续查询中过滤掉了使用过的电话号码,所以我认为我可以完全删除重复数据删除部分。
  • 我随机发现,在某些情况下,UPDATE_DATE 完全相同,因此我必须在分区的 ORDER BY 中添加另一个字段。

此外,这里还有一些关于进一步 select 语句的更多见解,这可能说明了为什么这不是一个容易放入 TVF 的查询。合并列中的差异对应于 select 语句中的不同输出列(有关 select 语句的示例,请参阅第一个编辑):

  1. SELECT @phone1 = COALESCE(CELL1, PERS1, BUS1, OTHER1, FAX1)
    ...
    WHERE CONTACT_ID = @key
    
  2. SELECT @phone2 = COALESCE(CELL2, PERS1, PERS2, BUS1, BUS2, OTHER1, OTHER2, FAX1, FAX2)
    ... 
    WHERE CONTACT_ID = @key
        AND PHONE_NUMBER NOT IN (SELECT PHONE_NUMBER FROM contact_phone WITH(NOLOCK)
            WHERE PHONE_ID IN (@phone1))
    
  3. SELECT @phone3 = COALESCE(CELL3, PERS1, PERS2, PERS3, BUS1, BUS2, BUS3, OTHER1, OTHER2, OTHER3, FAX1, FAX2, FAX3)
    ...
    WHERE CONTACT_ID = @key
        AND PHONE_NUMBER NOT IN (SELECT PHONE_NUMBER FROM contact_phone WITH(NOLOCK)
            WHERE PHONE_ID IN (@phone1,@phone2))
    

查看 [RANKED_PHONE]:

SELECT PHONE_ID
    , CONTACT_KEY
    , TYPE_CD
    , PHONE_NUMBER
    , ROW_NUMBER() OVER(
        PARTITION BY CONTACT_KEY,TYPE_CD
        ORDER BY UPDATE_DATE DESC, [PRIMARY] DESC
    ) PHONE_RANK
FROM contact_phone WITH(NOLOCK)

指数:

CONSTRAINT [PK_contactphone_PHONEID] PRIMARY KEY ([PHONE_ID])

CREATE NONCLUSTERED INDEX [NIX_contactphone_UPDATEDATE_PRIMARY] ON [contact_phone] ([UPDATE_DATE],[PRIMARY])
GO

CREATE NONCLUSTERED INDEX [NIX_contactphone_CONTACTKEY_TYPECD_PHONENUMBER] ON [contact_phone] ([CONTACT_KEY],[TYPE_CD],[PHONE_NUMBER])
GO

最佳答案

如果你改变了

的定义
CREATE NONCLUSTERED INDEX [NIX_contactphone_CONTACTID_TYPECD_PHONENUMBER]
  ON [contact_phone] ([CONTACT_ID], [TYPE_CD], [PHONE_NUMBER])

CREATE NONCLUSTERED INDEX [NIX_contactphone_CONTACTID_TYPECD_PHONENUMBER]
  ON [contact_phone] ([CONTACT_ID], [TYPE_CD], [PHONE_NUMBER], PHONE_ID DESC) 
  INCLUDE (UPDATE_DT)

(注意:虽然这似乎包含一个额外的键列,但实际情况并非如此。无论如何,聚集索引键都会添加到所有非唯一非聚集索引的键中。但是,显式添加它允许 ASC/DESC 待定义。)

该索引确实有一个额外的 INCLUDE -d 列来覆盖查询。

并将查询更改为

SELECT PHONE_ID,
       CONTACT_ID,
       TYPE_CD,
       ROW_NUMBER() OVER( PARTITION BY CONTACT_ID, TYPE_CD 
                              ORDER BY UPDATE_DT DESC ) AS PHONE_RANK
FROM   (SELECT PHONE_ID,
               CONTACT_ID,
               TYPE_CD,
               UPDATE_DT,
               RANK() OVER (PARTITION BY CONTACT_ID, TYPE_CD, PHONE_NUMBER 
                                        ORDER BY PHONE_ID DESC) AS PHONE_ID_RANK
        FROM   contact_phone
        ) nodupes 
        WHERE PHONE_ID_RANK = 1

这稍微改进了计划。

Plan

CONTACT_ID, TYPE_CD, PHONE_NUMBER, PHONE_ID DESC的第一个分区使用的顺序与查询第二部分 CONTACT_ID, TYPE_CD,UPDATE_DT 所需的不匹配尽管如此,你总会得到一种排序。

关于SQL Server - 子查询中分组依据的索引效率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17250218/

相关文章:

c# - 使用 ASP.net Web 显示数据库中的内容进行循环

sql - SQL Server 中的完全递归员工-老板关系

SQL SELECT... WHERE with REPLACE - 担心效率低下

sql - 查找表中具有相关最大日期行列匹配值的行?

sql - 在单个 SQL 查询中查询相似但不相交的数据集

sql-server-2008 - 大量插入索引较高的子项(Sql Server 2008)

sql - 我应该拆分 SQL Server 表吗?

php - SQL 语法错误似乎可以找到正确的查询

python - 索引错误: shape mismatch: indexing arrays could not be broadcast together with shapes

sql - 什么时候应该使用全文索引?