需要帮助来提高一些 TSQL“不存在”的查询性能

Posted

技术标签:

【中文标题】需要帮助来提高一些 TSQL“不存在”的查询性能【英文标题】:Needing help to improve some TSQL "not exists" query performance 【发布时间】:2013-06-04 12:46:33 【问题描述】:

我在对包含 750 000 个条目的表运行查询时遇到性能问题。执行需要 15 到 20 秒,在此期间阻止对数据库的访问并创建大量错误日志(当然还有愤怒的客户)。

这里是查询:

DECLARE @FROM_ID AS UNIQUEIDENTIFIER = 'XXX'
DECLARE @TO_ID AS UNIQUEIDENTIFIER = 'YYY'

update tbl_share
set user_id = @TO_ID 
where user_id = @FROM_ID
and not exists (
    select *
    from tbl_share ts
    where ts.file_id = file_id
    and ts.user_id = @TO_ID
    and ts.corr_id = corr_id
    and ts.local_group_id = local_group_id
    and ts.global_group_id = global_group_id 
)

我现在有点卡住了,因为我的 TSQL 知识有限。 我想知道是否:

我应该创建一个临时表 我应该选择“*”以外的其他内容

我没有太多机会运行测试,因为它是一个生产数据库,并且每天有 10-20 个客户永久连接。

感谢您的帮助!

【问题讨论】:

这个好像没用:and ts.corr_id = corr_id and ts.local_group_id = local_group_id and ts.global_group_id = global_group_id @RBarryYoung 哦,谢谢,我会修改我的神话 另一种提高性能的方法可能是使用公用表表达式 (CTE)。 @Tim Schmelter:是的。 @sjkm:“是的,确实如此”的意思是,是的,它没用?整个条件没有意义,因为您需要使用第一个表,例如:where ts.file_id = tbl_share.file_id 而不是 ts.file_id = file_id,这始终是正确的。 @BorisDelormas - 不,不是。它正在将子查询中的值与其自身进行比较。非限定列名从最近的范围向外解析。我之前发布的 SQL Fiddle 链接修复了该特定问题。 【参考方案1】:

重组你的代码逻辑怎么样?

DECLARE @FROM_ID AS UNIQUEIDENTIFIER = 'XXX'
DECLARE @TO_ID AS UNIQUEIDENTIFIER = 'YYY'

IF NOT EXISTS (select *
    from tbl_share ts
    where ts.user_id = @TO_ID)
BEGIN

    update tbl_share
    set user_id = @TO_ID 
    where user_id = @FROM_ID

END

因此,您事先进行了检查,仅在需要时才更新数据库。

HTH

【讨论】:

感谢您的方法,但我不能,因为我必须保持约束 ts.corr_id = corr_id and ts.local_group_id = local_group_id and ts.global_group_id = global_group_id跨度> 好的,我想你缺少一些索引,例如NOT EXISTS 语句中包含的所有列之一。创建非集群索引 [IX_TBL_SHARE_EXISTS] ON [TBL_SHARE](file_id, user_id, corr_id, local_group_id, global_group_id) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS , ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]【参考方案2】:

让我们从优化选择开始。 检查查询计划。 如果那是PK那么它是碎片化的吗?

select * 
from tbl_share
where user_id = @FROM_ID
and not exists (
    select *
    from tbl_share ts
    where ts.file_id = file_id
    and ts.user_id = @TO_ID
    and ts.corr_id = corr_id
    and ts.local_group_id = local_group_id
    and ts.global_group_id = global_group_id 
    )

select tUpdate.* 
from tbl_share as tUpdate
left outer join tbl_share as tExists 
  on tUpdate.user_id = @FROM_ID
 and tExists.user_id = @TO_ID
 and tExists.file_id = tUpdate.file_id
 and tExists.corr_id = tUpdate.corr_id
 and tExists.local_group_id = tUpdate.local_group_id
 and tExists.global_group_id = tUpdate.global_group_id 
where tExists.user_id is null 

【讨论】:

以上是关于需要帮助来提高一些 TSQL“不存在”的查询性能的主要内容,如果未能解决你的问题,请参考以下文章

在提高 SQL Query 的查询性能方面需要帮助

需要帮助来提高 MYSQL 子查询性能

TSQL - 排除与临时表匹配的行

帮助提高查询的性能

Mysql:如果不存在则执行。是不是可以提高性能?

不存在的 TSQL 循环