MySQL:加入vs WHERE性能

MySQL:加入vs WHERE性能,mysql,sql,query-performance,Mysql,Sql,Query Performance,问题:在对这两个查询进行性能比较时,我应该考虑什么 查询: vs 事实上,他们也是这样做的,但在其他方面 另外,仅仅在我的服务器上启动并查看响应时间是不够的。我想了解两者的区别,并了解当我的db长大后会发生什么。根据我的说法,你只想问哪个更好。关联子查询或SQL联接。解释如下:- 一种相关子查询,即where条件取决于从包含查询的行中获得的值的子查询,将为每行执行一次。一种非相关子查询或sql联接,其中where条件独立于包含的查询,将在开始时执行一次。SQL引擎会自动进行这种区分 因此,据我所

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

查询:

vs

事实上,他们也是这样做的,但在其他方面


另外,仅仅在我的服务器上启动并查看响应时间是不够的。我想了解两者的区别,并了解当我的db长大后会发生什么。

根据我的说法,你只想问哪个更好。关联子查询或SQL联接。解释如下:-

一种相关子查询,即where条件取决于从包含查询的行中获得的值的子查询,将为每行执行一次。一种非相关子查询或sql联接,其中where条件独立于包含的查询,将在开始时执行一次。SQL引擎会自动进行这种区分


因此,据我所知,join将给出比相关子查询更快的结果。但在实际情况下,您必须检查这些查询在您的系统上的性能以及实际结果。

根据我的说法,您只想问哪个更好。关联子查询或SQL联接。解释如下:-

一种相关子查询,即where条件取决于从包含查询的行中获得的值的子查询,将为每行执行一次。一种非相关子查询或sql联接,其中where条件独立于包含的查询,将在开始时执行一次。SQL引擎会自动进行这种区分


因此,据我所知,join将给出比相关子查询更快的结果。但在实际情况下,您必须检查系统上这些查询的性能以及实际结果。

编写SQL查询时,性能并不总是主要选项。为了可读性,我会选择第一个查询。请给我另一个@id_表的记录引用的表的记录。这很简单,易于阅读。至于性能:您可以通过主键访问一条记录,也可以通过主键访问另一个表中的另一条记录。这很难再快了

第二条语句连接两个表以获取id。顺便说一下,所选id缺少限定符t。因此,它也是如此,但乍一看并不明显。连接两个表,但将其限制为另一个带有@id的_表记录,并提供表的id。这意味着相同,但让dbms可以自由选择如何执行它。例如,它可以先加入所有记录,然后删除@id不匹配的所有记录。然而,一个好的dbms不能做到这一点;它将创建与语句1相同的执行计划


好的dbms会检测到这样的情况,它们会在内部重新编写qwueries,发现查询的含义相同,并得出相同的执行计划。这是越来越好,但它并不总是完美的工作。因此,有时候,如何写陈述确实很重要。当语句变得更复杂时,有时第二种语法会连接所有内容并过滤所需内容,从而产生更好的执行计划。不幸地因此,您通常必须在可读性和性能之间做出决定。我通常尽可能地编写可读的查询,并且仅在遇到性能问题时才对其进行更改。

编写SQL查询时,性能并不总是主要选项。为了可读性,我会选择第一个查询。请给我另一个@id_表的记录引用的表的记录。这很简单,易于阅读。至于性能:您可以通过主键访问一条记录,也可以通过主键访问另一个表中的另一条记录。这很难再快了

第二条语句连接两个表以获取id。顺便说一下,所选id缺少限定符t。因此,它也是如此,但乍一看并不明显。连接两个表,但将其限制为另一个带有@id的_表记录,并提供表的id。这意味着相同,但让dbms可以自由选择如何执行它。例如,它可以先加入所有记录,然后删除@id不匹配的所有记录。然而,一个好的dbms不能做到这一点;它将创建与语句1相同的执行计划


好的dbms会检测到这样的情况,它们会在内部重新编写qwueries,发现查询的含义相同,并得出相同的执行计划。这是越来越好,但它并不总是完美的工作。因此,有时候,如何写陈述确实很重要。当语句变得更复杂时,有时第二种语法会连接所有内容并过滤所需内容,从而产生更好的执行计划。不幸地因此,您通常必须在可读性和性能之间做出决定。我通常将查询写得尽可能可读,只有在遇到性能问题时才对其进行更改。

,只需稍加调查

艾尔,我同意上面的观点,可读性很重要 虽然我发现联接可读,但子查询可读性较差,尽管在本例中,子查询非常简单,因此无论哪种方式都不是主要问题

通常我希望MySQL能够优化一个不相关的子查询,并像连接一样高效地执行它。这个子查询乍一看似乎是不相关的,即它的结果不依赖于包含的查询

但是,在SQL fiddle上使用时,情况似乎并非如此:-

使用子查询时,解释说这是一个不可缓存的子查询,从手册中可以看出:-

无法缓存其结果并且必须为外部查询的每一行重新计算结果的子查询

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

我的感觉是,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   

只需要一点点调查

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

通常我希望MySQL能够优化一个不相关的子查询,并像连接一样高效地执行它。这个子查询乍一看似乎是不相关的,即它的结果不依赖于包含的查询

但是,在SQL fiddle上使用时,情况似乎并非如此:-

使用子查询时,解释说这是一个不可缓存的子查询,从手册中可以看出:-

无法缓存其结果并且必须为外部查询的每一行重新计算结果的子查询

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

我的感觉是,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   

你能比较一下性能吗不,你得自己比较一下。我们没有你的服务器和数据库,我们甚至不知道你创建了哪些索引。@TimSchmelter抱歉,我的意思是,当一个索引可能比另一个更好时,你给了我理由。当然,我可以在我的服务器上检查它。但我想了解两个查询之间的区别。此外,当my DB长大后,性能特征可能会改变。@V_B检查此链接可能对您有帮助@Sadikhasan谢谢,有用的参考您可以比较性能否,您必须自己比较。我们没有你的服务器和数据库,我们甚至不知道你创建了哪些索引。@TimSchmelter抱歉,我的意思是,当一个索引可能比另一个更好时,你给了我理由。当然,我可以在我的服务器上检查它。但我想了解两个查询之间的区别。此外,当my DB长大后,性能特征可能会改变。@V_B check此链接可能对您有所帮助@Sadikhasan谢谢,有用的参考它似乎不是相关的子查询。它不依赖于外部查询。但总的来说,联接的执行速度肯定会比子查询快。@AnkitBajpai是的,id值是常量。但是感谢这些信息,我不知道连接通常比相关子查询执行得更快的原因是,对于相关子查询,查询必须从主查询中获取所有行,然后对于每一行,它必须执行子查询。使用联接,它只需执行一次查询。即使是针对非相关子查询的查询,它也可以只执行一次子查询以覆盖所有行。然而,还有一些问题。如果对子查询进行连接,该子查询返回了许多记录,其中大部分记录被忽略,那么对子查询结果进行连接可能会产生很大的开销。它似乎不是一个相关的子查询。它不依赖于外部查询。但总的来说,联接的执行速度肯定会比子查询快。@AnkitBajpai是的,id值是常量。但是谢谢你提供的信息,我不知道
连接执行速度通常比相关子查询快的原因是,对于相关子查询,查询必须从主查询中获取所有行,然后对于每一行,它必须执行子查询。使用联接,它只需执行一次查询。即使是针对非相关子查询的查询,它也可以只执行一次子查询以覆盖所有行。然而,还有一些问题。如果针对一个子查询进行连接,该子查询返回了许多记录,其中大部分记录被忽略,那么针对其结果进行连接可能会带来很大的开销。Kettener您认为:MySQL是一个好的dbms吗?虽然我赞同编写可读性,但我不能说我发现第一个查询更可读。对我来说,它不那么可读。在sqlfiddle上玩MySQL似乎由于某种奇怪的原因没有想出相同的执行计划它似乎已经决定第一个子查询被视为不可缓存SUBQUERY@V_B:好问题我不知道,我自己也没有使用过MySQL。我认为它是一个很好的dbms,但我也读到过它的查询优化器有时在找到完美的执行计划时遇到问题,特别是在子查询时。快速谷歌搜索给了我这个:。子查询优化似乎是MySQL的一个弱点。Kickstart的检查证实了这一点。@Kickstart:关于可读性,至少有人第一眼看到查询1试图选择id=。。。。我不认为这会更具可读性。但是,好吧,这可能是一个人习惯的。如果MySQL不能很好地处理子查询,您将日复一日地避免它们,并且您习惯于读取连接而不是子查询。在我习惯的Oracle中,您甚至可以在元组上编写子句,这非常方便。至于MySQL的查询优化器:他们希望现在知道自己的问题,并正在改进它。一些问题正在解决。您链接的页面上有一个链接,提供了MySQL 5.6改进的详细信息。您可以很高兴地在MySQL的子查询中使用它,尽管对于子查询的大结果,它的优化效果很差,而这对我来说是使其可读性降低的原因之一。对我来说,在返回结果时,我想到的是带有常见或不常见分组的重叠集,而while中的子查询感觉像是偏离了集合。但是我同意这在很大程度上是你所习惯的。Kettener你怎么认为:MySQL是一个好的dbms?虽然我赞同写可读性,但我不能说我觉得第一个查询更可读。对我来说,它不那么可读。在sqlfiddle上玩MySQL似乎由于某种奇怪的原因没有想出相同的执行计划它似乎已经决定第一个子查询被视为不可缓存SUBQUERY@V_B:好问题我不知道,我自己也没有使用过MySQL。我认为它是一个很好的dbms,但我也读到过它的查询优化器有时在找到完美的执行计划时遇到问题,特别是在子查询时。快速谷歌搜索给了我这个:。子查询优化似乎是MySQL的一个弱点。Kickstart的检查证实了这一点。@Kickstart:关于可读性,至少有人第一眼看到查询1试图选择id=。。。。我不认为这会更具可读性。但是,好吧,这可能是一个人习惯的。如果MySQL不能很好地处理子查询,您将日复一日地避免它们,并且您习惯于读取连接而不是子查询。在我习惯的Oracle中,您甚至可以在元组上编写子句,这非常方便。至于MySQL的查询优化器:他们希望现在知道自己的问题,并正在改进它。一些问题正在解决。您链接的页面上有一个链接,提供了MySQL 5.6改进的详细信息。您可以很高兴地在MySQL的子查询中使用它,尽管对于子查询的大结果,它的优化效果很差,而这对我来说是使其可读性降低的原因之一。对我来说,在返回结果时,我想到的是带有常见或不常见分组的重叠集,而while中的子查询感觉像是偏离了集合。但我同意这在很大程度上是你习惯的。谢谢!伟大的回答!谢谢伟大的回答!