长时间运行的查询永远在SQL Server中执行

时间:2016-12-20 17:39:52

标签: sql sql-server tsql

在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 :-

enter image description here

2 个答案:

答案 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执行的数据修改产生轻微影响。所以你想做一点测试。