执行计划显示了一种排序 - 但由于查询无法解决

Execution Plan shows a sort - but can't figure a way around because of query

这是我的查询——最后一个查询是让我痛苦的原因: address.postcode字段是一个varchar(14),可以看到用户输入的输入格式。

DECLARE @ZipCode NVARCHAR(MAX) = ('06409;06471;11763;06443;06371;11949;11946;11742')

IF OBJECT_ID('tempdb..#ZipCodes') IS NOT NULL DROP TABLE #ZipCodes;

CREATE TABLE #ZipCodes (
Zipcode NVARCHAR(6)
)

INSERT INTO #ZipCodes ( Zipcode )
SELECT zip.Token + '%'
FROM DMS.fn_SplitList(@ZipCode, ';')  zip

CREATE NONCLUSTERED INDEX [idx_Zip] ON #ZipCodes (Zipcode)

IF OBJECT_ID('tempdb..#ZipCodesConstituents') IS NOT NULL DROP TABLE #ZipCodesConstituents;

CREATE TABLE #ZipCodesConstituents (
ConstituentID UNIQUEIDENTIFIER
, PostCode NVARCHAR(12)
)
CREATE NONCLUSTERED INDEX [idx_ZipCodesConstituents] ON #ZipCodesConstituents (ConstituentID, PostCode)

INSERT INTO #ZipCodesConstituents ( ConstituentID, PostCode )
SELECT a.CONSTITUENTID
, a.POSTCODE
FROM #ZipCodes zip
JOIN DMS.address  a  
    ON a.POSTCODE LIKE zip.Zipcode  
where a.ISPRIMARY = 1

我正在尝试附上执行计划 -- 但没有成功... 基本上代码部分的估计成本为 61.9% 并且排序是 61.5%

我试图评估行为,但在我的测试中,我无法在最后 INSERT 中强制使用排序运算符。但是我看到的是下面两个问题

  1. 你创建索引,然后插入到table。这可能是有害的。并非在所有情况下,但它可能会在您的查询中强制排序,因为 SQL 服务器会尝试确保插入期间的正确顺序以帮助索引重新组织。
  2. 您使用 UNIQUEIDENTIFIER 作为您的主键。这在某种程度上可能很有用,但我认为在您的情况下,一个简单的 IDENTITY(1,1) 列就足够了,不是吗?索引中的 UNIQUEIDENTIFIER 将严重强制碎片化。以这种方式解决它可能不是最好的主意。

我用 100.000 行的测试集测试了这两个变体。 这些是我衡量执行成本的结果:

  • 在所有情况下,如果在 #ZipCodesConstituentsINSERT 之后 创建索引,成本就会显着降低。
  • 使用 INDENTITY 而不是 UNIQUEIDENTIFIER 将进一步提高性能。
  • 如果您的 运行 这种查询更频繁,那么在您的地址 table 上添加索引是明智的。

以下是成本点 (cp) 的测量值 - 越低越好:

  • UniqueIdentifier + 之前的索引:Insert.
  • 20 cp
  • UniqueIdentifier + 插入后的索引:Insert 为 8 cp + 索引为 7(其中出现 SORT)。
  • Identity + 之前的索引:Insert
  • 18 cp
  • Identity + 之后的索引:Insert 7 cp + 索引
  • 6
  • Identity + Index after + Index on Address: 3 for the Insert + 6 for the Index

获胜者是:Identity 列 + 索引,也许还有 Address 上的索引。

我用来提升两个语句(UniqueIdentifierIdentity)的索引是这个:

CREATE NONCLUSTERED INDEX [NCI_Adress_IsPrimary_Postcode]
ON Address ([IsPrimary],[PostCode])
INCLUDE ([Constituentid])

在我的测试用例中,构建它需要 13 cp。如果您只使用一次,那将无济于事!如果您经常使用此语句,甚至有时 day/week 它可能对您有用。

希望这能解决您的问题。