8种常见SQL错误用法,你中招了吗( 二 )

由于 is_reply 只有0和1两种状态 , 我们按照下面的方法重写后 , 执行时间从1.58秒降低到2毫秒 。

8种常见SQL错误用法,你中招了吗

文章插图
 
5、EXISTS语句
MySQL 对待 EXISTS 子句时 , 仍然采用嵌套子查询的执行方式 。如下面的 SQL 语句:
8种常见SQL错误用法,你中招了吗

文章插图
 
执行计划为:
+----+--------------------+-------+------+-----+------------------------------------------+---------+-------+---------+ -----+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+--------------------+-------+------+ -----+------------------------------------------+---------+-------+---------+ -----+| 1 | PRIMARY | n | ALL | | NULL | NULL | NULL | 1086041 | Using where || 1 | PRIMARY | sra | ref | | idx_user_id | 123 | const | 1 | Using where || 2 | DEPENDENT SUBQUERY | m | ref | | idx_message_info | 122 | const | 1 | Using index condition; Using where |+----+--------------------+-------+------+ -----+------------------------------------------+---------+-------+---------+ -----+去掉 exists 更改为 join , 能够避免嵌套子查询 , 将执行时间从1.93秒降低为1毫秒 。
8种常见SQL错误用法,你中招了吗

文章插图
 
新的执行计划:
+----+-------------+-------+--------+ -----+------------------------------------------+---------+ -----+------+ -----+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+-------+--------+ -----+------------------------------------------+---------+ -----+------+ -----+| 1 | SIMPLE | m | ref | | idx_message_info | 122 | const | 1 | Using index condition || 1 | SIMPLE | n | eq_ref | | PRIMARY | 122 | ighbor_id | 1 | Using where || 1 | SIMPLE | sra | ref | | idx_user_id | 123 | const | 1 | Using where |+----+-------------+-------+--------+ -----+------------------------------------------+---------+ -----+------+ -----+6、条件下推
外部查询条件不能够下推到复杂的视图或子查询的情况有:
  • 聚合子查询;
  • 含有 LIMIT 的子查询;
  • UNION 或 UNION ALL 子查询;
  • 输出字段中的子查询;
【8种常见SQL错误用法,你中招了吗】如下面的语句 , 从执行计划可以看出其条件作用于聚合子查询之后:
8种常见SQL错误用法,你中招了吗

文章插图
 
+----+-------------+------------+-------+---------------+-------------+---------+-------+------+-------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+------------+-------+---------------+-------------+---------+-------+------+-------------+| 1 | PRIMARY | <derived2> | ref | <auto_key0> | <auto_key0> | 514 | const | 2 | Using where || 2 | DERIVED | operation | index | idx_4 | idx_4 | 519 | NULL | 20 | Using index |+----+-------------+------------+-------+---------------+-------------+---------+-------+------+-------------+确定从语义上查询条件可以直接下推后 , 重写如下:
8种常见SQL错误用法,你中招了吗

文章插图
 
执行计划变为:
+----+-------------+-----------+------+---------------+-------+---------+-------+------+--------------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+-----------+------+---------------+-------+---------+-------+------+--------------------+| 1 | SIMPLE | operation | ref | idx_4 | idx_4 | 514 | const | 1 | Using where; Using index |+----+-------------+-----------+------+---------------+-------+---------+-------+------+--------------------+7、提前缩小范围
先上初始 SQL 语句:
8种常见SQL错误用法,你中招了吗

文章插图
 
该SQL语句原意是:先做一系列的左连接 , 然后排序取前15条记录 。从执行计划也可以看出 , 最后一步估算排序记录数为90万 , 时间消耗为12秒 。
+----+-------------+-------+--------+---------------+---------+---------+-----------------+--------+----------------------------------------------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+-------+--------+---------------+---------+---------+-----------------+--------+----------------------------------------------------+| 1 | SIMPLE | o | ALL | NULL | NULL | NULL | NULL | 909119 | Using where; Using temporary; Using filesort || 1 | SIMPLE | u | eq_ref | PRIMARY | PRIMARY | 4 | o.uid | 1 | NULL || 1 | SIMPLE | p | ALL | PRIMARY | NULL | NULL | NULL | 6 | Using where; Using join buffer (Block Nested Loop) |+----+-------------+-------+--------+---------------+---------+---------+-----------------+--------+----------------------------------------------------+


推荐阅读