强制并行联合执行

Posted

技术标签:

【中文标题】强制并行联合执行【英文标题】:Force parallel union execution 【发布时间】:2019-08-16 09:13:37 【问题描述】:

我有一个从六个相同类型的表中收集数据的查询。为了创建最终选择,我使用 UNION ALL。不幸的是,优化器会依次扫描六个表中的每一个,然后将它们收集到一个表中。有没有办法让优化器并行扫描表?

  |--Concatenation
       |--Index Scan(OBJECT:([EGeoCache].[NonClusteredIndex-20190815-105027] AS [GC]))
       |--Index Scan(OBJECT:([YGeoCache].[NonClusteredIndex-20190814-103125] AS [GC]))
       |--Index Scan(OBJECT:([GGeoCache].[NonClusteredIndex-20190814-103358] AS [GC]))
       |--Index Scan(OBJECT:([HGeoCache].[NonClusteredIndex-20190814-103422] AS [GC]))
       |--Index Scan(OBJECT:([DGeoCache].[NonClusteredIndex-20190814-103305] AS [GC]))
       |--Index Scan(OBJECT:([SGeoCache].[NonClusteredIndex-20190814-103457] AS [GC]))

SELECT
    VEGC.AddressID
  , VEGC.Lat
  , VEGC.Lon
FROM    vEGeoCache AS VEGC
UNION ALL
SELECT
    VYGC.AddressID
  , VYGC.Lat
  , VYGC.Lon
FROM    vYGeoCache AS VYGC
UNION ALL
SELECT
    VGGC.AddressID
  , VGGC.Lat
  , VGGC.Lon
FROM    vGGeoCache AS VGGC
UNION ALL
SELECT
    VHGC.AddressID
  , VHGC.Lat
  , VHGC.Lon
FROM    vHGeoCache AS VHGC
UNION ALL
SELECT
    VDGC.AddressID
  , VDGC.Lat
  , VDGC.Lon
FROM    vDGeoCache AS VDGC
UNION ALL
SELECT
    VSGC.AddressID
  , VSGC.Lat
  , VSGC.Lon
FROM    vSGeoCache AS VSGC

【问题讨论】:

这是一个非常好的问题。我不认为有办法让这些并行运行,但我很想知道是否有办法。 由于无法准确复现你的情况,我从多个表中选择了相同类型的字段,并行执行,开启Include LIve Query Statistics,甚至可以看到并行。 表是否在不同的设备(或内存驻留)上,以便并行执行不会造成 I/O 瓶颈?否则,不清楚您期望从并行执行中获得什么好处。 【参考方案1】:

要强制执行并行执行计划,您可以使用需要系统管理员权限的OPTION (QUERYTRACEON 8649)。在 SQL Server 2016+ 上,您可以使用不需要系统管理员权限的 OPTION(USE HINT('ENABLE_PARALLEL_PLAN_PREFERENCE'))

QUERYTRACEON 8649 和 ENABLE_PARALLEL_PLAN_PREFERENCE 都没有记录,这意味着它们在生产环境中运行是不安全的(在我的书中)。您的第三个选择是使用 Adam Machanic 的Make_Parallel,这不是无证的(它只是使用旧学校的数学)。

使用每个看起来像这样:

...
FROM    vDGeoCache AS VDGC
UNION ALL
SELECT
    VSGC.AddressID
  , VSGC.Lat
  , VSGC.Lon
FROM    vSGeoCache AS VSGC
OPTION (QUERYTRACEON 8649);

...
FROM    vDGeoCache AS VDGC
UNION ALL
SELECT
    VSGC.AddressID
  , VSGC.Lat
  , VSGC.Lon
FROM    vSGeoCache AS VSGC
OPTION(USE HINT('ENABLE_PARALLEL_PLAN_PREFERENCE'))

...
FROM    vDGeoCache AS VDGC
UNION ALL
SELECT
    VSGC.AddressID
  , VSGC.Lat
  , VSGC.Lon
FROM    vSGeoCache AS VSGC
CROSS JOIN dbo.make_parallel();

Make_parallel 是最安全的方法,但会创建一个臃肿的执行计划。 我这样做的方式是:我在 Dev 的测试中使用 OPTION (QUERYTRACEON 8649)。需要注意的最重要的事情是,这些选项不能保证并行计划。确保在打开“包括实际执行计划”的情况下运行查询,以查看它是否正常工作。如果有任何并行性抑制组件(例如标量 UDF 作为计算列或检查约束),则不会强制执行并行计划。如果我确定强制执行并行计划是可行的方法(强制执行极其谨慎),那么我在生产中使用 make_parallel。

【讨论】:

以上是关于强制并行联合执行的主要内容,如果未能解决你的问题,请参考以下文章

MySQL学习笔记连接子分页联合查询以及sql语句执行顺序总结

4. SQL — 表的联合

sql之强制索引

CUDA学习和总结1

类型化对象联合上的详尽映射

联合索引和多个单列索引选择