加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程 > 正文

sql-server – 为什么子查询使用并行性而不是连接?

发布时间:2020-12-31 15:30:30 所属栏目:编程 来源:网络整理
导读:为什么SQL Server在运行使用子查询的查询时会使用并行性,但在使用连接时却不然?连接版本以串行方式运行,完成时间大约需要30倍. 加入版本:~30secs 子查询版本: 1秒 编辑: Xml版本的查询计划: JOIN version SUBQUERY version 解决方法 正如评论中已经指出

为什么SQL Server在运行使用子查询的查询时会使用并行性,但在使用连接时却不然?连接版本以串行方式运行,完成时间大约需要30倍.

加入版本:~30secs

子查询版本:< 1秒 编辑:
Xml版本的查询计划:

JOIN version

SUBQUERY version

解决方法

正如评论中已经指出的那样,您似乎需要更新统计信息.

从位置和测试之间的连接中出来的估计行数在两个计划之间是非常不同的.

加入计划估算:1

子查询计划估计:8,748

从连接中出来的实际行数是14,276.

当然,绝对没有直觉意味着连接版本应该估计3行应该来自位置并产生单个连接行,而子查询估计这些行中的单个行将从同一连接产生8,748但是我仍然是能够重现这一点.

如果在创建统计信息时直方图之间没有交叉,则似乎会发生这种情况.连接版本假定为单行.并且子查询的单个相等性查找假设与对未知变量的相等性搜索相同的估计行.

测试的基数是26244.假设有三个不同的位置ID,则以下查询估计将返回8,748行(26244/3)

declare @i int

SELECT *
FROM   testruns AS tr
WHERE  tr.location_id = @i

鉴于表位置只包含3行,很容易(如果我们假设没有外键)来设计创建统计信息的情况,然后以显着影响返回的实际行数但不足的方式更改数据跳转统计信息的自动更新并重新编译阈值.

由于SQL Server获取了来自该连接的行数所以错误,因此连接计划中的所有其他行估计都被大大低估了.除了意味着您获得了一个串行计划之外,查询还获得了不足的内存授权,并且排序和散列连接溢出到tempdb.

重现计划中显示的实际行与估计行的一种可能方案如下.

CREATE TABLE location
  (
     id       INT CONSTRAINT locationpk PRIMARY KEY,location VARCHAR(MAX) /*From the separate filter think you are using max?*/
  )

/*Temporary ids these will be updated later*/
INSERT INTO location
VALUES      (101,'Coventry'),(102,'Nottingham'),(103,'Derby')

CREATE TABLE testruns
  (
     location_id INT
  )

CREATE CLUSTERED INDEX IX ON testruns(location_id)

/*Add in 26244 rows of data split over three ids*/
INSERT INTO testruns
SELECT TOP (5984) 1
FROM   master..spt_values v1,master..spt_values v2
UNION ALL
SELECT TOP (5984) 2
FROM   master..spt_values v1,master..spt_values v2
UNION ALL
SELECT TOP (14276) 3
FROM   master..spt_values v1,master..spt_values v2

/*Create statistics. The location_id histograms don't intersect at all*/
UPDATE STATISTICS location(locationpk) WITH FULLSCAN;    
UPDATE STATISTICS testruns(IX) WITH FULLSCAN;

/* UPDATE location.id. Three row update is below recompile threshold*/
UPDATE location
SET    id = id - 100

然后运行以下查询给出相同的估计与实际差异

SELECT *
FROM   testruns AS tr
WHERE  tr.location_id = (SELECT id
                         FROM   location
                         WHERE  location = 'Derby')

SELECT *
FROM   testruns AS tr
       JOIN location loc
         ON tr.location_id = loc.id
WHERE  loc.location = ( 'Derby' )

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读