【问题标题】:Optimize TSQL query with 3 tables使用 3 个表优化 SQL 查询
【发布时间】:2013-02-05 14:32:25
【问题描述】:

我需要从数据库中获取所有的运行,但是需要标记本次运行是否有错误。

3 个表格:

  • 运行:包含运行)
  • Runfiles:包含运行期间处理的文件 ID
  • 消息:包含错误、警告、...

这个查询可以进一步优化吗?

SELECT TOP 1000 runid, 
            start, 
            end, 
            userid, 
            CASE 
              WHEN EXISTS(SELECT rf.fk_fileid 
                          FROM   runfiles rf 
                          WHERE  rf.fk_runid = r.runid 
                                 AND EXISTS(SELECT m.messageid 
                                            FROM   messages m 
                                            WHERE  m.fk_fileid = 
                                                   rf.fk_fileid 
                                                   AND m.fk_statusid = 4)) 
            THEN 1 
              ELSE 0 
            END                 AS ContainsError
FROM   runs r 
ORDER  BY start DESC 

请不要评论表名,它们是为这个问题翻译的。

谢谢!

【问题讨论】:

  • 查看执行计划并添加适当的索引
  • “优化”是什么意思?如果您询问性能,那么您应该包括查询中的执行计划。如果您要问的是提高可读性或可维护性,那么code review site 会是一个更好的提问地点。
  • 有时您只需要比较不同的选项。您是否在运行文件和消息上尝试过左连接?
  • @Nullius 我有一篇博文可能会有所帮助:foliotek.com/devblog/…
  • 查询在我看来很好,性能问题可能是因为缺少索引。

标签: sql-server tsql optimization query-optimization


【解决方案1】:

试试这个:

SELECT TOP 1000
     r.runid
    ,r.start
    ,r.[end]
    ,r.userid
    ,CASE WHEN m.messageid IS NOT NULL THEN 1 ELSE 0 END AS ContainsError
FROM runs r
LEFT JOIN runfiles rf
    ON rf.fk_runid = r.runid
LEFT JOIN [messages] m
    ON m.fk_fileid = rf.fk_fileid
    AND m.fk_statusid = 4
ORDER BY r.start DESC

选择列表中的任何内容都会针对结果集中的每一行运行。这意味着您的 CASE 语句中的嵌套子查询正在为每个 TOP 1000 行执行。

使用左连接和CASE 语句检查主键是否为空,允许将整个语句作为一个集合进行评估,SQL Server 就是这样做的。这种方式应该会表现得更好。

【讨论】:

  • 关系 Run RunFile 是一对多的,关系 Runfile Message 也是一对多的。因此,此查询将多次返回相同的运行。也许有一种方法可以限制连接中的结果数量。我会调查的。谢谢!
猜你喜欢
  • 1970-01-01
  • 2012-08-16
  • 2020-08-08
  • 1970-01-01
  • 2016-12-08
  • 2021-12-08
  • 2016-04-15
  • 1970-01-01
相关资源
最近更新 更多