我有一个涉及两个表的查询:表A有很多行,并包含一个名为的字段b_id,该字段引用表中的记录B,该表有大约30个不同的行.表上A有一个索引b_id,表上B有一个索引name.
我的查询看起来像这样:
SELECT COUNT(A.id) FROM A INNER JOIN B ON B.id = A.b_id WHERE (B.name != 'dummy') AND <condition>;
Run Code Online (Sandbox Code Playgroud)
随着condition桌子上的一些随机条件A(我有很多,所有表现出相同的行为).
此查询非常慢(以2秒为单位),并使用说明,显示查询优化器以表开始,B提供约29行,然后扫描表A.做一个STRAIGHT_JOIN,转动订单,查询立即运行.
我不是黑魔法的粉丝,所以我决定尝试别的东西:拿出B名字的记录的id,dummy比方说23,然后将查询简化为:
SELECT COUNT(A.id) FROM A WHERE (b_id != 23) AND <condition>;
Run Code Online (Sandbox Code Playgroud)
令我惊讶的是,这个查询实际上比直接连接要慢,向北走一秒钟.
关于为什么连接比简化查询更快的任何想法?
更新:根据评论中的请求,解释的输出:
直接加入:
+----+-------------+-------+--------+-----------------+---------+---------+---------------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-----------------+---------+---------+---------------+--------+-------------+
| 1 | SIMPLE | A | ALL | b_id | NULL | NULL | NULL | 200707 | Using where |
| 1 | SIMPLE | B | eq_ref | PRIMARY,id_name | PRIMARY | 4 | schema.A.b_id | 1 | Using where |
+----+-------------+-------+--------+-----------------+---------+---------+---------------+--------+-------------+
Run Code Online (Sandbox Code Playgroud)
没有加入:
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | A | ALL | b_id | NULL | NULL | NULL | 200707 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
Run Code Online (Sandbox Code Playgroud)
更新2:尝试了另一种变体:
SELECT COUNT(A.id) FROM A WHERE b_id IN (<all the ids except for 23>) AND <condition>;
这比无连接运行得更快,但仍然比连接慢,所以似乎不等操作负责部分性能命中,但不是全部.
也许这应该是评论而不是答案,但会有点长。
首先,很难相信两个具有(几乎)完全相同的解释的查询以不同的速度运行。此外,如果解释中带有额外行的运行速度更快,则这种可能性较小。我想“更快”这个词是这里的关键。
您已经比较了速度(完成查询所需的时间),这是一种极其经验性的测试方法。例如,您可能不正确地禁用了缓存,这使得该比较毫无用处。更不用说您<insert your preferred software application here>在运行测试时可能会发生页面错误或任何其他操作,这可能会导致查询速度降低。
衡量查询性能的正确方法是基于解释(这就是它存在的原因)
因此,我必须回答的最接近的问题是:关于为什么联接比简化查询更快的任何想法?...简而言之,是第 8 层错误。
不过,我确实还有一些其他评论,应该考虑这些评论以加快速度。如果A.id是主键(名字听起来就是这样),根据你的解释,为什么必须count(A.id)扫描所有行?它应该能够直接从索引获取数据,但我Using index在额外的标志中没有看到。看来您甚至没有唯一索引,并且它不是不可为空的字段。这也闻起来很奇怪。确保该字段不为空并且其上有唯一索引,再次运行解释,确认额外标志包含,Using index然后(正确)计时查询。它应该运行得更快。
另请注意,与我上面提到的相同的性能改进方法是将替换count(A.id)为count(*).
只是我的2分钱。
| 归档时间: |
|
| 查看次数: |
779 次 |
| 最近记录: |