Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 选择“慢”,因为未使用内部联接_Mysql_Sql_Inner Join_Innodb - Fatal编程技术网

Mysql 选择“慢”,因为未使用内部联接

Mysql 选择“慢”,因为未使用内部联接,mysql,sql,inner-join,innodb,Mysql,Sql,Inner Join,Innodb,我有两张桌子: CREATE TABLE `A` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`), ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ; CREATE TABLE `B` ( `id` int(11) NOT NULL AUTO_INCREMENT, `a_id` int(11) NOT NULL, `c_id` int(11) NOT NULL, PRIMARY

我有两张桌子:

CREATE TABLE `A` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
CREATE TABLE `B` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `a_id` int(11) NOT NULL,
  `c_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `IX_a_id` (`a_id`),
  KEY `IX_c_id` (`c_id`),
  CONSTRAINT `a_id_ibfk_1` FOREIGN KEY (`a_id`) REFERENCES `A` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
他们每人有几百万行

explain select count(*) FROM B inner join A on B.a_id = A.id WHERE B.c_id = 7;
+----+-------------+-------+--------+-----------------------+------------+---------+--------------------+--------+-------------+
| id | select_type | table | type   | possible_keys         | key        | key_len | ref                | rows   | Extra       |
+----+-------------+-------+--------+-----------------------+------------+---------+--------------------+--------+-------------+
|  1 | SIMPLE      | B     | ref    | IX_a_id,IX_c_id       | IX_c_id    | 4       | const              | 116624 | Using where |
|  1 | SIMPLE      | A     | eq_ref | PRIMARY               | PRIMARY    | 4       | test1.B.a_id       |      1 | Using index |
+----+-------------+-------+--------+-----------------------+------------+---------+--------------------+--------+-------------+
现在,我不明白为什么mysql不能忽略一个不需要的内部连接,这会降低性能。i、 例如,以下查询相当于上述查询:

select count(*) from B where B.c_id = 7
这应该很容易推断,因为B.a_id不能为null,并且B.a_id对唯一键a.id有约束


有没有办法让mysql理解这一点?

包含联接的SQL语句将扫描这两个表,并在进行联接之前将它们加载到临时存储中。这意味着它将两个表加载到一个临时表中,对不必要的重复项进行排序和删除,并返回结果。通过使用子查询作为要联接的表,可以加快这一速度

例如,如果您执行了以下操作,您将不太可能受到绩效处罚:

select count(*) FROM 
(select * from B where B.c_id = 7 and B.a_id is not Null) as sub_b
inner join 
(select * from A where A.id is not Null) as sub_a
on (sub_b.a_id = sub_a.id);
这是因为SQL的行为与您预期的一样,并且预过滤要连接的结果,从而减少了加载到它的临时表中的量。使用A上id的索引以及B上c_id和A_id的索引,可以进一步加快速度

如果有大量列,减少查询中返回的列数也会加快查询速度:

select count(sub_b.a_id) FROM 
(select a_id from B where B.c_id = 7 and B.a_id is not Null) as sub_b
inner join 
(select id from A where A.id is not Null) as sub_a
on (sub_b.a_id = sub_a.id);
----编辑----

下面提出了一个很好的观点,第二个选择是不必要的。第一个子选择确保首先应用我们关心的where子句

试试这个:

select count(sub_b.a_id) FROM 
(select a_id from B where B.c_id = 7) as sub_b
inner join A on (sub_b.a_id = A.id);
现在,我不明白为什么mysql不能忽略一个不需要的内部连接,这会降低性能

解决这个隐含的问题


提交一份bug报告来建议这样的优化

您是否尝试指定要计数的列而不是*?类似于:从B中选择count(B.C_id),其中B.C_id=7Good point Steffo,但是,这仅在返回大量列时才起作用。在这个can中,select*将返回4,而select B.c_id返回1。由于count(*)对行进行计数,这不太可能对联接中的4列和1列产生太大的影响。count(B.a_id)对count(*)没有任何影响。有一种方法可以让MySQL理解。省略不需要的连接。你让它加入一些东西,它加入了,现在你希望计算机能够猜出程序员的意思。认真地另外,影响性能的因素是innodb_buffer_pool_大小不足120%,但与其直面核心问题,不如直言不讳,对吧?索引联接应该不会影响性能。至于连接是否不必要,可以使用
左连接
,但如果将其设置为
内部连接
,则暗示您只希望匹配第二个表中也匹配的行。或者换句话说,通过将
内部联接放在那里,您就可以使它成为需要的。您的两个查询不相等1)您描述的用于实现连接的合并连接算法有时会使用,但并不总是使用。2) 我看不出上面这些会有什么不同。i、 例如,您添加的“is not null”语句没有任何意义,因为相关列被定义为not null。我看不出盲目地从中选择所有行有助于mysql判断连接是不需要的。(我确实尝试了上面的方法,我可以确认它实际上在性能方面更差)空值的优点,我已经更新了。子选择的目的是只将您关心的记录加入到联接中。然后,SQL应该以您期望的方式响应,放弃与A的连接。B.c_id、B.A_id和A.id上的索引应该提高它的性能