SQL Server 2005 中的 UNION ALL 性能 [英] UNION ALL Performance IN SQL Server 2005

查看:73
本文介绍了SQL Server 2005 中的 UNION ALL 性能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有一长串 CTE 的查询,以

I have a query with a long chain of CTEs which ends with

SELECT RegionName, AreaName, CityName, SubCityName, StreetName 
FROM tDictionaryStreets
UNION ALL
SELECT RegionName, AreaName, CityName, SubCityName, StreetName 
FROM tDictionaryRegions

此查询的执行时间为 1450 毫秒.当我分别执行这 2 个 SELECT 时,它花费的时间要少得多.对于查询

The execution time of this query is 1450 ms. When I execute these 2 SELECTs separatly it takes much less time. For the query

SELECT RegionName, AreaName, CityName, SubCityName, StreetName 
FROM tDictionaryStreets

执行时间为 106 毫秒.而对于查询

execution time is 106 ms. And for the query

SELECT RegionName, AreaName, CityName, SubCityName, StreetName 
FROM tDictionaryRegions

是 20 毫秒.

为什么 UNION ALL 将执行时间增加了 10 倍以上?我可以做些什么来减少它?

Why UNION ALL increases the execution time in more than 10 times? What can I do to decrease it?

感谢您的帮助.

更新整个查询(我缩短了它,但问题仍然存在)是

UPDATED The whole query (I shortened it, but the problem still presents) is

WITH tFoundRegions AS
(
    SELECT KladrItemName FROM dbo.tBuiltKladrItemsWithQuants
    WHERE UserID = @UserID AND (indeces & 1) > 0
),
tFoundAreas AS
(
    SELECT KladrItemName FROM dbo.tBuiltKladrItemsWithQuants
    WHERE UserID = @UserID AND (indeces & 2) > 0
),
tFoundCities AS
(
    SELECT KladrItemName FROM dbo.tBuiltKladrItemsWithQuants
    WHERE UserID = @UserID AND (indeces & 4) > 0
),
tFoundSubCities AS
(
    SELECT KladrItemName FROM dbo.tBuiltKladrItemsWithQuants
    WHERE UserID = @UserID AND (indeces & 8) > 0
),
tFoundStreets AS
(
    SELECT KladrItemName FROM dbo.tBuiltKladrItemsWithQuants
    WHERE UserID = @UserID AND (indeces & 16) > 0
),
tDictionaryStreets AS
(
    SELECT DISTINCT
        CASE WHEN RegionName IN (SELECT KladrItemName FROM tFoundRegions) THEN RegionName ELSE NULL END RegionName
      , CASE WHEN AreaName IN (SELECT KladrItemName FROM tFoundAreas) THEN AreaName ELSE NULL END AreaName
      , CASE WHEN CityName IN (SELECT KladrItemName FROM tFoundCities) THEN CityName ELSE NULL END CityName
      , CASE WHEN SubCityName  IN (SELECT KladrItemName FROM tFoundSubCities) THEN SubCityName ELSE NULL END SubCityName
      , StreetName 
    FROM StreetNames
    WHERE StreetName IN (SELECT KladrItemName FROM tFoundStreets)
),
tMissingSubCities AS
(
    SELECT KladrItemName FROM tFoundSubCities
    WHERE KladrItemName NOT IN (SELECT SubCityName FROM tDictionaryStreets)
),
tDictionarySubCities AS
(
    SELECT DISTINCT 
        CASE WHEN RegionName IN (SELECT KladrItemName FROM tFoundRegions) THEN RegionName ELSE NULL END RegionName
      , CASE WHEN AreaName IN (SELECT KladrItemName FROM tFoundAreas) THEN AreaName ELSE NULL END AreaName
      , CASE WHEN CityName IN (SELECT KladrItemName FROM tFoundCities) THEN CityName ELSE NULL END CityName
      , SubCityName
      , NULL StreetName 
    FROM SubCityNames
    WHERE SubCityName IN (SELECT KladrItemName FROM tMissingSubCities)
)
SELECT RegionName, AreaName, CityName, SubCityName, StreetName 
FROM tDictionaryStreets
UNION ALL
SELECT RegionName, AreaName, CityName, SubCityName, StreetName 
FROM tDictionarySubCities

推荐答案

确保在每次测试运行之间清除执行 + 数据缓存.

Make sure you clear the execution + data caches between each test run.

例如

DBCC FREEPROCCACHE
DBCC DROPCLEANBUFFERS

如果你先用 UNION ALL 运行,然后再分别运行 2 个选择,数据将已经缓存在内存中,从而使性能更好(因此给人一种错误的印象,即后续方法可能不会更快).

If you run with the UNION ALL first, and then run the 2 selects separately afterwards, the data will already be cached in memory making performance much better (therefore giving the false impression that the subsequent approach is quicker when it may not be).

如果您使用了 UNION,那么它可能会更慢,因为它必须应用 DISTINCT,但 UNION ALL 不必这样做,所以它应该没有什么不同.

If you used a UNION then that may well be slower as it has to apply a DISTINCT, but UNION ALL doesn't have to do that so it should be no different.

更新:
查看执行计划并比较它们 - 看看是否有任何区别.在运行查询之前,您可以通过单击 SSMS 中的包括实际执行计划"按钮来查看执行计划

Update:
Have a look at the execution plans and compare them - see if there is any difference. You can view the execution plan by clicking the "Include Actual Execution Plan" button in SSMS before running the query

更新 2:
根据给出的完整 CTE,我想我会考虑优化它们 - 我认为 UNION ALL 实际上不是问题所在.

Update 2:
Based on full CTEs given, I think I'd be looking at optimising those - I don't think the UNION ALL is actually the problem.

恕我直言,最好的尝试是逐个处理 CTE,并尝试单独优化每个 CTE,这样当您将它们全部组合到主查询中时,它们的性能会更好.

IMHO, best thing to try is work through the CTEs one by one and try to optimise each one individually so that when you then combine them all in the main query, they perform better.

例如对于 tDictionaryStreets,试试这个怎么样:

e.g. for tDictionaryStreets, how about trying this:

SELECT DISTINCT
    r.KladrItemName AS RegionName,
        a.KladrItemName AS AreaName,
        c.KladrItemName AS CityName,
        sc.KladrItemName AS SubCityName,
        s.StreetName      
FROM StreetNames s
    JOIN tFoundStreets fs ON s.StreetName = fs.KladrItemName
    LEFT JOIN tFoundRegions r ON s.RegionName = r.KladrItemName
    LEFT JOIN tFoundAreas a ON s.AreaName = a.KladrItemName
    LEFT JOIN tFoundCities c ON s.CityName = c.KladrItemName
    LEFT JOIN tFoundSubCities sc ON s.SubCityName = scc.KladrItemName

每个表上的 KladrItemName 至少应该有一个索引.尝试以同样的方式使用连接重新处理 tDictionarySubCities.

KladrItemName on each table should at least have an index on. Try reworking tDictionarySubCities in the same kind of way with joins too.

这篇关于SQL Server 2005 中的 UNION ALL 性能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆