在SQL Server中优化以下SQL查询的最佳方法是什么。我尝试在连接列上添加聚集索引,但没有运气,SQL一直在运行。有人可以帮我解决这个问题。谢谢。
InputTable - 466K行 RefTable - 45k行
Input Data Distribution :-
240360 rows L1( NOT NULL ),L2( NOT NULL ),L3( NULL ),L4( NULL )
225776 rows L1( NULL ),L2( NULL ),L3( NULL ),L4( NULL )
ref表中没有NULL值。
SELECT tg.guidExternal,
tg.areascheme,
tg.latitude,
tg.longitude,
tg.guidremodel,
tg.countrycode,
tg.areacode,
tg.subareaname,
tg.postalname
INTO #tmpRef
FROM RefTable tg WHERE areascheme = 1003
SELECT
l.locationsid,
tg.guidExternal,
tg.areascheme,
tg.latitude,
tg.longitude,
tg.guidremodel AS guidExternalModel
INTO #initFromOut
FROM #tmpRef tg
JOIN
InputTable l
ON --tg.areascheme = l.areascheme
tg.countrycode = l.strareabriefnamel1
AND ( CASE WHEN l.strareabriefnamel2 IS NULL THEN '' ELSE tg.areacode END ) = COALESCE( l.strareabriefnamel2,'' )
AND ( CASE WHEN l.strareabriefnamel3 IS NULL THEN '' ELSE tg.subareaname END ) = COALESCE( l.strareabriefnamel3,'' )
AND ( CASE WHEN l.strareabriefnamel4 IS NULL THEN '' ELSE tg.postalname END ) = COALESCE( l.strareabriefnamel4,'' )
--( l.strareabriefnamel2 IS NULL OR tg.areacode = l.strareabriefnamel2 ) AND
--( l.strareabriefnamel3 IS NULL OR tg.subareaname = l.strareabriefnamel3 ) AND
--( l.strareabriefnamel4 IS NULL OR tg.postalname = l.strareabriefnamel4 ) AND
--l.locationsid NOT IN ( SELECT locationsid FROM #tGeocodedLocations )
Execution Plan :-
答案 0 :(得分:0)
我认为#tmpRef是一个地址数据库。
你在InputTable中每行收到45k行(来自#RefTable的所有行),其中strareabriefnamel2是,而strareabriefnamel3为null而strareabriefnamel4为null
例如,如果输入表包含1000行只包含国家/地区代码,则会在结果中收到45M行,依此类推。
你应该重写WHERE条件,如下所示:
(l.strareabriefname2=tg.areacode OR
(l.strareabriefname2 IS NULL AND tg.areacode IS NULL
) AND ...
在这种情况下,如果areacode为null,则只查找国家/地区,而不是国家/地区的所有记录。
P.S。 你也应该在国家代码上的#refTable索引,strareabriefname2,strareabriefname3,strareabriefname4
答案 1 :(得分:0)
首先,第一个插入语句只是浪费时间 - 您可以在第二个语句中加入RefTable而不是#tmpRef。
接下来,当您必须在NULLABLE列上具有复杂的连接条件时,您不是在使用非常好的设计。这个SELECT语句是什么杀了你:
SELECT l.locationsid,
tg.guidExternal,
tg.areascheme,
tg.latitude,
tg.longitude,
tg.guidremodel AS guidExternalModel
INTO #initFromOut
FROM #tmpRef tg
JOIN InputTable l
ON --tg.areascheme = l.areascheme
tg.countrycode = l.strareabriefnamel1
AND ( CASE WHEN l.strareabriefnamel2 IS NULL THEN '' ELSE tg.areacode END ) = COALESCE( l.strareabriefnamel2,'' )
AND ( CASE WHEN l.strareabriefnamel3 IS NULL THEN '' ELSE tg.subareaname END ) = COALESCE( l.strareabriefnamel3,'' )
AND ( CASE WHEN l.strareabriefnamel4 IS NULL THEN '' ELSE tg.postalname END ) = COALESCE( l.strareabriefnamel4,'' )
这两个表上的保证扫描和执行计划中的低效合并连接。一个可行的替代方案是创建一个索引视图,如下所示:
CREATE VIEW dbo.yourView
WITH SCHEMABINDING AS
SELECT l.locationsid,
tg.guidExternal,
tg.areascheme,
tg.latitude,
tg.longitude,
tg.guidremodel AS guidExternalModel
FROM RefTable tg
JOIN InputTable l
ON tg.countrycode = l.strareabriefnamel1
AND ( CASE WHEN l.strareabriefnamel2 IS NULL THEN '' ELSE tg.areacode END ) = COALESCE( l.strareabriefnamel2,'' )
AND ( CASE WHEN l.strareabriefnamel3 IS NULL THEN '' ELSE tg.subareaname END ) = COALESCE( l.strareabriefnamel3,'' )
AND ( CASE WHEN l.strareabriefnamel4 IS NULL THEN '' ELSE tg.postalname END ) = COALESCE( l.strareabriefnamel4,'' )
WHERE tg.areascheme = 1003;
GO
CREATE UNIQUE CLUSTERED INDEX uci_yourview ON dbo.yourView(guidExternal)
-- your unique key would likely be different this is just a thought based on what info is available.
然后填充#initFromOut既快又简单:
SELECT * INTO #initFromOut FROM dbo.yourView;
缺点是这会对针对您的RefTable和InputTable执行的数据修改产生轻微影响。所以你想做一点测试。