SQL 查询需要一个多小时才能执行 200k 行

Posted

技术标签:

【中文标题】SQL 查询需要一个多小时才能执行 200k 行【英文标题】:SQL query takes more than an hour to execute for 200k rows 【发布时间】:2016-12-23 13:11:39 【问题描述】:

我有两个表,每个表大约有 200,000 行。我已经运行了下面的查询,运行一个多小时后仍然没有完成。对此有何解释?

SELECT 
    dbo.[new].[colom1],
    dbo.[new].[colom2],
    dbo.[new].[colom3],
    dbo.[new].[colom4],  
    dbo.[new].[Value] as 'nieuwe Value',
    dbo.[old].[Value] as 'oude Value'
FROM dbo.[new]
JOIN dbo.[old] 
    ON dbo.[new].[colom1] = dbo.[old].[colom1] 
    and dbo.[new].[colom2] = dbo.[old].[colom2] 
    and dbo.[new].[colom3] = dbo.[old].[colom3] 
    and dbo.[new].[colom4] = dbo.[old].[colom4] 
where dbo.[new].[Value] <> dbo.[old].[Value]

来自评论;

【问题讨论】:

您可能被锁定了。尝试使用 with (nolock) 来验证。请务必添加执行计划。 一次 200,000 行太多了,性能应该很慢。尝试使用分页并在一页中显示 10 - 20 个数据。这可能会有所帮助。 我无法制定执行计划,因为它不会执行查询,所以我会先删除一些行,裸露在我身上 让我们continue this discussion in chat. @Fredou 怎么样?对于那些不知道JOININNER JOIN 在功能上相同的人来说,我能想到的唯一方法是从可读性的角度来看...... 【参考方案1】:

似乎对于单列上的相等连接,连接键中具有 NULL 值的行被过滤掉了,但对于多列上的连接,情况并非如此。 结果,哈希连接复杂度从 O(N) 变为 O(N^2)。

================================================ ========================

在这种情况下,我想推荐一篇由 Paul White 撰写的关于类似问题的精彩文章 - Hash Joins on Nullable Columns

================================================ ========================

我已经生成了这个用例的小型模拟,我鼓励您测试您的解决方案。

create table mytab1 (c1 int null,c2 int null)
create table mytab2 (c1 int null,c2 int null)

;with t(n) as (select 1 union all select n+1 from t where n < 10)
insert into mytab1 select null,null from t t0,t t1,t t2,t t3,t t4

insert into mytab2 select null,null from mytab1

insert into mytab1 values (111,222);
insert into mytab2 values (111,222);

select * from mytab1 t1 join mytab2 t2 on t1.c1 = t2.c1 and t1.c2 = t2.c2 

对于 OP 查询,我们应该删除任何连接键列中具有 NULL 值的行。

SELECT 
    dbo.[new].[colom1],
    dbo.[new].[colom2],
    dbo.[new].[colom3],
    dbo.[new].[colom4],  
    dbo.[new].[Value] as 'nieuwe Value',
    dbo.[old].[Value] as 'oude Value'
FROM dbo.[new]
JOIN dbo.[old] 
    ON dbo.[new].[colom1] = dbo.[old].[colom1] 
    and dbo.[new].[colom2] = dbo.[old].[colom2] 
    and dbo.[new].[colom3] = dbo.[old].[colom3] 
    and dbo.[new].[colom4] = dbo.[old].[colom4] 
where dbo.[new].[Value] <> dbo.[old].[Value]
    and dbo.[new].[colom1]  is not null
    and dbo.[new].[colom2]  is not null
    and dbo.[new].[colom3]  is not null
    and dbo.[new].[colom4]  is not null
    and dbo.[old].[colom1]  is not null
    and dbo.[old].[colom2]  is not null
    and dbo.[old].[colom3]  is not null
    and dbo.[old].[colom4]  is not null

【讨论】:

【参考方案2】:

使用 EXCEPT 连接,您只需对那些已更改的值进行更大的 HASH 连接,速度快得多:

/*
create table [new] ( colom1  int, colom2  int, colom3  int, colom4  int, [value]  int)
create table [old] ( colom1  int, colom2  int, colom3  int, colom4  int, [value]  int)

insert old values (1,2,3,4,10)
insert old values (1,2,3,5,10)
insert old values (1,2,3,6,10)
insert old values (1,2,3,7,10)
insert old values (1,2,3,8,10)
insert old values (1,2,3,9,10)


insert new values (1,2,3,4,11)
insert new values (1,2,3,5,10)
insert new values (1,2,3,6,11)
insert new values (1,2,3,7,10)
insert new values (1,2,3,8,10)
insert new values (1,2,3,9,11)
*/

select n.colom1, n.colom2 , n.colom3, n.colom4, n.[value] as newvalue, o.value as oldvalue
from new n
inner join [old] o on n.colom1=o.colom1 and n.colom2=o.colom2 and n.colom3=o.colom3 and n.colom4=o.colom4
inner join 
(
select colom1, colom2 , colom3, colom4, [value] from new
except
select colom1, colom2 , colom3, colom4, [value] from old
) i on n.colom1=i.colom1 and n.colom2=i.colom2 and n.colom3=i.colom3 and n.colom4=i.colom4

【讨论】:

以上是关于SQL 查询需要一个多小时才能执行 200k 行的主要内容,如果未能解决你的问题,请参考以下文章

如何调查为什么每天运行2分钟的sql脚本需要2个小时?

120K 条记录的 SQL 查询耗时 9 小时

MySql Query - 使用 varchars、索引进行优化,需要一个多小时才能运行

SQL 性能:SELECT DISTINCT 与 GROUP BY

加速oracle SQL查询

SQL 命令运行缓慢。需要帮助识别缓慢