2015-02-11 69 views
0

我有这种形式的MySQL查询:SELECT中的子查询或JOIN中的子查询?

SELECT 
    employee.name, 
    totalpayments.totalpaid 
FROM 
    employee 
    JOIN (
     SELECT 
      paychecks.employee_id, 
      SUM(paychecks.amount) totalpaid 
     FROM 
      paychecks 
     GROUP BY 
      paychecks.employee_id 
     ) totalpayments on totalpayments.employee_id = employee.id 

我最近发现,它返回快得多这种形式:

SELECT 
    employee.name, 
    (
     SELECT 
      SUM(paychecks.amount) 
     FROM 
      paychecks 
     WHERE 
      paychecks.employee_id = employee.id 
    ) totalpaid 
FROM 
    employee 

我很惊讶会有的速度差,并且较低的查询会更快。我更喜欢开发的上层表单,因为我可以独立运行子查询。

有没有办法获得“两全其美”:快速结果返回并能够独立运行子查询?

回答

0

有可能的,相关子查询能够有效地利用索引,这就是为什么它的快速,即使该子查询必须被执行多次的。

对于带内联视图的第一个查询,导致MySQL创建派生表,对于大集合,这实际上是MyISAM表。

在MySQL 5.6.x及更高版本中,优化程序可能会选择在派生表上添加索引,如果这允许执行ref操作并且ref操作的估计成本低于嵌套循环扫描。

我建议您尝试使用EXPLAIN来查看访问计划。 (根据你的业绩报告,我怀疑你是在MySQL 5.5版运行或更早)。


这两种说法并不完全等同,在那里有在employees行的情况下对其中有没有匹配paychecks中的行。

的等效结果可以完全获得避免子查询:

SELECT e.name 
    , SUM(p.amount) AS total_paid 
    FROM employee e 
    JOIN paychecks p 
    ON p.employee_id = e.id 
GROUP BY e.id 

(使用一个内连接以获得等同于所述第一查询的结果,使用一个LEFT外部联接以等同于所述第二查询。如果要在工资中找不到与空值为amount的匹配行时返回0而不是NULL值,则将SUM()聚合包括在IFNULL函数中。)

+0

非常感谢,spencer7593!我可以尝试在派生表上强制索引吗? (我不太熟悉索引或创建它们的语法。) – 2015-02-11 17:26:40

+0

@YossiFendel:我不相信在派生表上创建索引有任何提示。这只会在版本5.6和更高版本中发生。 EXPLAIN输出应显示正在使用哪种连接操作。通过完全避免子查询可能获得最佳性能。我在编辑答案时提供了一个示例。 – spencer7593 2015-02-11 17:31:42

+0

@YossiFendel:另一个选项是创建一个临时表(带索引)作为子查询的结果,然后在第二个查询中引用该临时表。这很麻烦,但它可以提高性能,特别是当多个查询中引用相同的内联视图时......因为我们避免了多次实现它。 – spencer7593 2015-02-11 17:36:42

0

加入基本上是笛卡尔产品那mea ns表A的所有记录将与表B的所有记录相结合的输出将是

number of records of table A * number of records of table b =rows in the new table 
10 * 10 = 100 

进出的100条记录,符合过滤器的那些会在查询返回。

在嵌套查询中,有一个示例内部查询,并且无论内部查询的记录的总大小是outter查询的输入,这就是为什么嵌套查询比连接速度更快的原因。

+0

是的,有时,SELECT列表中的相关子查询比联接操作更快,但通常情况并非如此。对创建笛卡尔乘积(m * n行),然后过滤出行的连接操作的描述并不是对JOIN操作实际操作方式的完全准确描述。要真正得到你描述的行为,你需要写一些能够创建笛卡尔积的东西,例如:'SELECT a.id,b.id FROM a JOIN b HAVING a.id = b.id'。但是,在WHERE子句或ON子句中使用连接谓词时,就不会发生。 – spencer7593 2015-02-11 17:43:51