尝试创建对此设置最有效的索引:
查看 (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 语句的示例,请参阅第一个编辑):
-
SELECT @phone1 = COALESCE(CELL1, PERS1, BUS1, OTHER1, FAX1) ... WHERE CONTACT_ID = @key
-
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))
-
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
这稍微改进了计划。
CONTACT_ID, TYPE_CD, PHONE_NUMBER, PHONE_ID DESC
的第一个分区使用的顺序与查询第二部分 CONTACT_ID, TYPE_CD,UPDATE_DT
所需的不匹配尽管如此,你总会得到一种排序。
关于SQL Server - 子查询中分组依据的索引效率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17250218/