MySQL:JOIN vs WHERE性能

时间:2014-06-05 08:57:40

标签: mysql sql query-performance

问题: 在对这两个查询进行效果比较时,我应该考虑什么?

查询:

SELECT id 
FROM table 
WHERE id = (
    SELECT table_id_fk 
    FROM another_table 
    WHERE id = @id
)

VS

SELECT id 
FROM table t 
JOIN another_table at
ON t.id = at.table_id_fk
WHERE at.id = @id

实际上他们也是这样,但在其他方面。

P.S。仅在我的服务器上启动它并查看响应时间是不够的。我想了解差异,并了解当我的数据库长大时会发生什么。

3 个答案:

答案 0 :(得分:2)

在编写SQL查询时,性能并不总是主要选项。我会选择第一个查询的可读性。 "给我带有@ id"的another_table记录引用的表的记录。这是直截了当的,易于阅读。至于性能:您通过主键访问一条记录,以按主键访问另一条记录(在另一个表中)。这很难得到更快。

第二个语句连接两个表以获取id(顺便说一下,所选id缺少限定符t)。所以它也是如此,但乍一看并不明显。 "加入两个表,但用@id将其限制在another_table记录中,并给我表#id;#34;。这意味着相同,但让dbms可以自由选择如何执行它。例如,它可以首先连接所有记录,然后删除@id不匹配的所有记录。然而,一个好的dbms不会这样做;它将创建与语句1相同的执行计划。

好的dbms检测到这样的情况,他们在内部重写qwueries,发现查询意味着相同并且达到相同的执行计划。这种情况越来越好,但它并不总能完美运作。所以有时如何编写语句也很重要。当语句变得更复杂时,有时候加入所有内容并过滤所需内容的第二种语法会带来更好的执行计划。不幸。因此,您经常需要在可读性和性能之间做出决定。我通常将查询编写为尽可能可读,并且仅在遇到性能问题时才更改它们。

答案 1 :(得分:1)

据我说,你只想问哪个更好。与Co相关的子查询或SQL Join。以下是解释: -

A "correlated subquery" (i.e., one in which the where condition depends on values obtained from the rows of the containing query) will execute once for each row. A non-correlated subquery or sql join (one in which the where condition is independent of the containing query) will execute once at the beginning. The SQL engine makes this distinction automatically.

因此,根据我的说法,加入将比相关的子查询给出更快的结果。但实际上,您必须检查系统上这些查询的性能以及实际结果。

答案 2 :(得分:1)

进行一点调查。

我同意上面的观点,可读性很重要,虽然我发现连接是可读的,而子查询我发现可读性较差(尽管在这种情况下,子查询非常简单,因此不是主要问题)。

通常情况下,我希望MySQL能够设法优化非相关的子查询并执行它,就像它是一个连接一样有效。乍一看这个子查询看起来确实是非相关的(即,它的结果不依赖于包含的查询)。

然而,在SQL小提琴上玩这种情况似乎并非如此: -

http://www.sqlfiddle.com/#!2/7696c/2

使用子查询,解释说这是一个 UNCACHEABLE SUBQUERY ,手册中有: -

无法缓存结果的子查询,必须为外部查询的每一行重新评估

通过指定值而不是将其作为变量传入来执行相同的子查询会给出不同的解释,并将其描述为 SUBQUERY 。我怀疑这和加入一样有效。

我的感觉是MySQL对变量的使用感到困惑,并且假设变量的值可以在行之间变化而计划查询。因此,它需要为每一行重新执行子查询。它还没有设法识别出查询中没有任何内容可以修改变量的值。

如果您想尝试自己,请在此处设置测试的详细信息: -

CREATE TABLE `table`
(
    id INT,
  PRIMARY KEY id(id)
);

CREATE TABLE another_table
(
    id INT,
    table_id_fk INT,
    PRIMARY KEY id (id),
    INDEX table_id_fk (table_id_fk)
);

INSERT INTO `table`
VALUES
(1),
(2),
(3),
(4),
(5),
(6),
(7),
(8);

INSERT INTO another_table
VALUES
(11,1),
(12,3),
(13,5),
(14,7),
(15,9),
(16,11),
(17,13),
(18,15);

要执行的SQL: -

SET @id:=13;

SELECT t.id 
FROM `table` t
WHERE id = (
    SELECT table_id_fk 
    FROM another_table 
    WHERE id = @id
);



SELECT t.id 
FROM `table` t 
JOIN another_table at
ON t.id = at.table_id_fk
WHERE at.id = @id;


SELECT t.id 
FROM `table` t
WHERE id = (
    SELECT table_id_fk 
    FROM another_table 
    WHERE id = 13
);

EXPLAIN SELECT t.id 
FROM `table` t
WHERE id = (
    SELECT table_id_fk 
    FROM another_table 
    WHERE id = @id
);



EXPLAIN SELECT t.id 
FROM `table` t 
JOIN another_table at
ON t.id = at.table_id_fk
WHERE at.id = @id;


EXPLAIN SELECT t.id 
FROM `table` t
WHERE id = (
    SELECT table_id_fk 
    FROM another_table 
    WHERE id = 13
);

解释结果: -

ID  SELECT_TYPE     TABLE   TYPE    POSSIBLE_KEYS   KEY     KEY_LEN     REF     ROWS    EXTRA
1   PRIMARY     t   index   (null)  PRIMARY     4   (null)  8   Using where; Using index
2   UNCACHEABLE SUBQUERY    another_table   const   PRIMARY     PRIMARY     4   const   1   

ID  SELECT_TYPE     TABLE   TYPE    POSSIBLE_KEYS   KEY     KEY_LEN     REF     ROWS    EXTRA
1   SIMPLE  at  const   PRIMARY,table_id_fk     PRIMARY     4   const   1   
1   SIMPLE  t   const   PRIMARY     PRIMARY     4   const   1   Using index

ID  SELECT_TYPE     TABLE   TYPE    POSSIBLE_KEYS   KEY     KEY_LEN     REF     ROWS    EXTRA
1   PRIMARY     t   const   PRIMARY     PRIMARY     4   const   1   Using index
2   SUBQUERY    another_table   const   PRIMARY     PRIMARY     4       1