多个内连接和子查询的查询优化
Posted
技术标签:
【中文标题】多个内连接和子查询的查询优化【英文标题】:Query optimization for multiple inner joins and sub-query 【发布时间】:2020-12-17 04:57:15 【问题描述】:我需要有关以下查询的查询优化方面的帮助。
SELECT pr.todate , pr.descr, cmp.company_id
FROM employee AS emp
INNER JOIN company AS cmp ON emp.emp_comp_id = cmp.company_id
INNER JOIN profile AS pr ON emp.acca_id = pr.profile_id
INNER JOIN acondition ON as_id = as_ac_id
WHERE as_closed = 0
AND (pr.ac_act_id = 20)
AND (pr.todate = (SELECT MIN(todate) AS Expr1
FROM profile pro
INNER JOIN employee empl ON empl.acca_id = pro.profile_id
JOIN acondition ON as_id = as_ac_id
WHERE (pro.ac_act_id = 20
AND empl.emp_comp_id = cmp.company_id)
AND as_closed = 0))
由于主查询和子查询有重复的join,有什么办法可以去掉子查询中的join?
【问题讨论】:
我们需要更多信息来帮助您……例如执行计划、表定义和表上的索引。是什么让您认为它可以优化? 嗨,employee
,company
,profile
有 nonclustered
索引,acondition
有 clustered
索引。有什么办法可以减少子查询中的内连接?
edit 请进入问题并使用粘贴计划来发布您的执行计划。为什么要删除连接?您的查询似乎完全合理。
有点慢,所以我需要优化这个查询。出于安全原因,我在这里使用了虚拟表,所以我可能无法共享执行计划
@the_coder_guy ,老实说,*** 并不是寻求查询调优建议的最佳场所。这需要与您进行大量的来回交流,并且还涉及很多事情。您最好的选择是查看 SQL Server 社区 slack 频道:dbatools.io/slack
【参考方案1】:
因为,正如您所澄清的,您的子查询几乎与您的主查询相同,您可以使用窗口函数 RANK
作为过滤条件。 RANK
为关系分配相同的编号,这意味着如果每个公司的多个记录匹配,您将获得所有记录,例如
SELECT todate, descr, company_id
FROM (
SELECT pr.todate, pr.descr, cmp.company_id
, RANK() OVER (PARTITION BY cmp.company_id ORDER BY pr.todate ASC) RankNumber
FROM employee AS emp
INNER JOIN company AS cmp ON emp.emp_comp_id = cmp.company_id
INNER JOIN profile AS pr ON emp.acca_id = pr.profile_id
INNER JOIN acondition ON as_id = as_ac_id
WHERE as_closed = 0 AND pr.ac_act_id = 20
) X
where RankNumber = 1;
【讨论】:
您好,感谢您的回复,这个查询只给了我一个结果,而我的原始查询给了我大约 35 个结果。 您好,我尝试调试,但无法弄清楚 where 子句中可能出现的问题。 以前的记录示例:2019-01-31 00:00:00.000 新员工 101 2020-11-27 00:00:00.000 老员工 014 2020-11-27 00:00:00.000 任期员工016 2020-12-11 00:00:00.000 新的初级员工 030 2020-11-27 00:00:00.000 董事 034 2020-12-14 00:00:00.000 初级经理 052 2019-02-18 00:00:00.000高级经理058 新记录输出:2019-01-31 00:00:00.000 新员工 101 它不应该只返回最旧的记录,它应该返回所有符合条件的记录。因此,如果我在没有 `AND (pr.todate = (SELECT MIN(todate) AS Expr1 FROM profile pro INNER JOIN employee empl ON empl.acca_id = pro.profile_id JOIN acondition ON as_id = as_ac_id WHERE (pro.ac_act_id = 20 AND empl.emp_comp_id = cmp.company_id) AND as_closed = 0)) `【参考方案2】:这对你有用吗?
SELECT ca.todate , pr.descr, cmp.company_id
FROM employee AS emp
INNER JOIN company AS cmp ON emp.emp_comp_id = cmp.company_id
CROSS APPLY (
SELECT TOP(1) pr.todate
FROM profile pr
INNER JOIN acondition ON as_id = as_ac_id
WHERE emp.acca_id = pr.profile_id AND (pr.ac_act_id = 20) AND as_closed = 0
ORDER BY pr.todate ASC
) AS ca
【讨论】:
嗨,在INNER JOIN acondition ON as_id = as_ac_id
的内部连接中,我出错了,因为它是配置文件表的一部分。
嗨,它没有给我正确的结果,我想min (todate )
标准没有得到应用。因此我得到了 49 个结果。
@Tole1010 你和我犯了同样的错误,你得到了一个分钟 todate
而不是每个公司一个。同样在您的情况下,您实际上并没有对您获得的日期应用任何过滤。
@Tole1010 有没有办法在这里添加日期的过滤条件?
您可以将结果插入临时表,然后在 todate 再次加入,但我不确定这是否会提高您的性能。如果您提供数据来填充表格,那么帮助您会容易得多。以上是关于多个内连接和子查询的查询优化的主要内容,如果未能解决你的问题,请参考以下文章