Rob*_*ini 1 performance sql-server execution-plan query-performance
我有大约 150 万条记录。此查询适用于较小的数据,但每几十万条记录就会慢一秒。对于 150 万,查询明显困难。
我模拟了一个全新的 Code First 项目来验证问题与我的实现无关,并提供以下示例查询:
SELECT TOP 1 Widgets.*
FROM [WidgetSandbox].[dbo].[Widgets] Widgets
INNER JOIN [WidgetSandbox].[dbo].[Status] Statuses ON Widgets.StatusId = Statuses.Id
INNER JOIN [WidgetSandbox].[dbo].[Colors] Colors ON Widgets.ColorCode = Colors.ColorCode
INNER JOIN [WidgetSandbox].[dbo].[Sizes] Sizes ON Widgets.SizeId = Sizes.Id
WHERE Statuses.Name = 'Available'
AND Colors.Name = 'Red'
ORDER BY Sizes.DiameterInches
Run Code Online (Sandbox Code Playgroud)
DiameterInches 是一个int
, 作为我实际代码中“PriorityLevel”的隐喻。
如果我注释掉ORDER BY Sizes.DiameterInches
,它会立即返回,但如果我想找到“最小的可用红色小部件”,它就会爬行。
有没有更好的办法?
执行计划 XML:https : //gist.github.com/RobertBaldini/57c8b61d135cc5c84c38b2da243611ad
DDL:https : //gist.github.com/RobertBaldini/3740c7bb85eea47d7fe63cb8602ac2d6
回购(数据加载器需要几分钟):https : //github.com/RobertBaldini/WidgetSandbox
您应该重新键入从nvarchar(max)到nvarchar([right size])的各种Name列。名称的长度不太可能达到 2GB,并且将它们设置为最大大小可以防止它们被用作索引中的键。一个好的一般经验法则是尽可能避免大对象数据类型。
您可能需要对 EF 代码进行更改,但在 T-SQL 中:
-- Guessing at 100 characters maximum
ALTER TABLE dbo.[Status]
ALTER COLUMN Name nvarchar(100) NOT NULL;
ALTER TABLE dbo.Colors
ALTER COLUMN Name nvarchar(100) NOT NULL;
ALTER TABLE dbo.Sizes
ALTER COLUMN Name nvarchar(100) NOT NULL;
ALTER TABLE dbo.Widgets
ALTER COLUMN Name nvarchar(100) NOT NULL;
Run Code Online (Sandbox Code Playgroud)
我还将列定义更改为NOT NULL
那里。
无论如何,给定索引:
CREATE NONCLUSTERED INDEX IX_dbo_Sizes__DiameterInches
ON dbo.Sizes (DiameterInches);
CREATE NONCLUSTERED INDEX IX_dbo_Widgets__SizeId_ColorCode_StatusId__Name
ON dbo.Widgets (SizeId, ColorCode, StatusId)
INCLUDE (Name);
Run Code Online (Sandbox Code Playgroud)
...您应该最终制定一个避免查找和排序的计划,例如:
由于Status和Colors 中的行数很少,现在可能不值得索引它们的Name列,但这可能会随着时间的推移而改变。在任何情况下,如果名称列应该是唯一的,您应该使用唯一约束或唯一非聚集索引来限制它们,例如:
CREATE UNIQUE NONCLUSTERED INDEX UQ_dbo_Colors__Name
ON dbo.Colors (Name);
CREATE UNIQUE NONCLUSTERED INDEX UQ_dbo_Status__Name
ON dbo.[Status] (Name);
CREATE UNIQUE NONCLUSTERED INDEX UQ_dbo_Sizes__Name
ON dbo.Sizes (Name);
CREATE UNIQUE NONCLUSTERED INDEX UQ_dbo_Widgets__Name
ON dbo.Widgets (Name);
Run Code Online (Sandbox Code Playgroud)
使用相同的索引,如果您能够更改 SQL,您还可以将颜色和状态查找分开:
DECLARE
@StatusId integer,
@ColorCode nvarchar(6);
SELECT @StatusId = ST.Id
FROM dbo.[Status] AS ST
WHERE ST.Name = N'Available';
SELECT @ColorCode = C.ColorCode
FROM dbo.Colors AS C
WHERE C.Name = N'Red';
SELECT TOP (1)
W.*
FROM dbo.Widgets AS W
JOIN dbo.Sizes AS S
ON W.SizeId = S.Id
WHERE
W.StatusId = @StatusId
AND W.ColorCode = @ColorCode
ORDER BY
S.DiameterInches;
Run Code Online (Sandbox Code Playgroud)
这使得一组更简单的操作也恰好使优化器的生活更轻松:
另请注意,Unicode 字符串文字应以 N 为前缀,以确保正确的数据类型。
哦,您还应该修补您的实例。它目前是 SQL Server 2008 Service Pack 1 - Service Pack 4已经推出一段时间了。
归档时间: |
|
查看次数: |
565 次 |
最近记录: |