执行计划显示了一种排序 - 但由于查询无法解决
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
中强制使用排序运算符。但是我看到的是下面两个问题
- 你创建索引,然后插入到table。这可能是有害的。并非在所有情况下,但它可能会在您的查询中强制排序,因为 SQL 服务器会尝试确保插入期间的正确顺序以帮助索引重新组织。
- 您使用
UNIQUEIDENTIFIER
作为您的主键。这在某种程度上可能很有用,但我认为在您的情况下,一个简单的 IDENTITY(1,1)
列就足够了,不是吗?索引中的 UNIQUEIDENTIFIER
将严重强制碎片化。以这种方式解决它可能不是最好的主意。
我用 100.000 行的测试集测试了这两个变体。
这些是我衡量执行成本的结果:
- 在所有情况下,如果在
#ZipCodesConstituents
的 INSERT
之后 创建索引,成本就会显着降低。
- 使用
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
上的索引。
我用来提升两个语句(UniqueIdentifier
和 Identity
)的索引是这个:
CREATE NONCLUSTERED INDEX [NCI_Adress_IsPrimary_Postcode]
ON Address ([IsPrimary],[PostCode])
INCLUDE ([Constituentid])
在我的测试用例中,构建它需要 13 cp。如果您只使用一次,那将无济于事!如果您经常使用此语句,甚至有时 day/week 它可能对您有用。
希望这能解决您的问题。
这是我的查询——最后一个查询是让我痛苦的原因: 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
中强制使用排序运算符。但是我看到的是下面两个问题
- 你创建索引,然后插入到table。这可能是有害的。并非在所有情况下,但它可能会在您的查询中强制排序,因为 SQL 服务器会尝试确保插入期间的正确顺序以帮助索引重新组织。
- 您使用
UNIQUEIDENTIFIER
作为您的主键。这在某种程度上可能很有用,但我认为在您的情况下,一个简单的IDENTITY(1,1)
列就足够了,不是吗?索引中的UNIQUEIDENTIFIER
将严重强制碎片化。以这种方式解决它可能不是最好的主意。
我用 100.000 行的测试集测试了这两个变体。 这些是我衡量执行成本的结果:
- 在所有情况下,如果在
#ZipCodesConstituents
的INSERT
之后 创建索引,成本就会显着降低。 - 使用
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 onAddress
: 3 for theInsert
+ 6 for the Index
获胜者是:Identity
列 + 索引,也许还有 Address
上的索引。
我用来提升两个语句(UniqueIdentifier
和 Identity
)的索引是这个:
CREATE NONCLUSTERED INDEX [NCI_Adress_IsPrimary_Postcode]
ON Address ([IsPrimary],[PostCode])
INCLUDE ([Constituentid])
在我的测试用例中,构建它需要 13 cp。如果您只使用一次,那将无济于事!如果您经常使用此语句,甚至有时 day/week 它可能对您有用。
希望这能解决您的问题。