多连接和多个子查询的sql性能比较

zsohkypk  于 2021-07-24  发布在  Java
关注(0)|答案(2)|浏览(420)

我知道以前有人问过这类问题,但我找不到一个和我的问题完全一样的问题。我试着举个夸张的例子。
假设我们希望找到至少有一名员工年龄大于40岁,至少有一名客户年龄小于20岁的公司。
我的同事为这个问题写的查询如下:

SELECT DISTINCT(c.NAME) FROM COMPANY c 
LEFT JOIN EMPLOYEE e ON c.COMPANY_ID = e.COMPANY_ID 
LEFT JOIN CUSTOMER u ON c.COMPANY_ID = u.COMPANY_ID
WHERE e.AGE > 40 and u.AGE < 20

我不熟悉数据库。但是看看这个查询(就像一个时间复杂性问题),它将创建一个不必要的巨大临时表。每个公司都有employeeamount x customeramount行。
因此,我重新编写了查询:

SELECT c.NAME FROM COMPANY c 
WHERE EXISTS (SELECT * FROM EMPLOYEE e WHERE e.AGE > 40 AND c.COMPANY_ID = e.COMPANY_ID  )
  OR EXISTS (SELECT * FROM CUSTOMER u WHERE u.AGE < 20 AND c.COMPANY_ID = u.COMPANY_ID )

我不知道这个查询是否会更糟,因为它将为每个公司运行2个子查询。
我知道有更好的方法来写这个。例如,为两个年龄条件编写两个不同的子查询,然后合并它们可能会更好。但是我真的很想知道两个查询中的一个或两个是否有问题。
注意:您可以增加联接/子查询的数量。例如,“我们希望找到至少有一名员工年龄大于40岁,至少有一名客户年龄小于20岁,并且至少有一个订单金额大于1000美元的公司。”
谢谢。

au9on6nz

au9on6nz1#

这个 exists 一般来说,版本应该有更好的性能,特别是当您在上有索引时 company_id 在每个子表中。
为什么?这个 JOIN 版本创建一个中间结果,所有客户超过40岁,所有员工低于20岁。如果这些团体对某一特定公司来说规模很大,那么规模可能会相当大。然后,查询执行额外的工作来删除重复项。
可能存在一些边缘情况,其中第一个版本具有良好的性能。举例来说,如果两个小组都是空的——没有20岁以下的员工,也没有40岁以上的顾客,我会想到这一点。然后中间结果集为空,不需要删除重复项。不过,对于一般情况,我建议 exists .

k4emjkb1

k4emjkb12#

要了解当前环境中实际发生的情况,需要使用数据库设置和数据来比较实际的执行计划(而不仅仅是解释计划,它只给出估计的计划)。除了oracle使用的详细步骤(全表扫描、连接等),只有真正的执行计划才能给出查询使用的详细资源,如cpu和io。
尝试:

ALTER SESSION STATISTICS_LEVEL=ALL;

<your query>

SELECT * FROM TABLE(dbms_xplan.display(NULL, NULL, format=>'allstats last'));

不要假设,只是测试。

相关问题