Common errors SQL usage, you caught it?

1, LIMIT statement

Paging query is one of the most frequently used scene, but also usually the most problematic areas. For simple statement such as the following, the general approach is to think of DBA on the type, name, create_time field plus a composite index. Such conditions can be effectively used to sort the index, to elevate performance.

SELECT * FROM   operation WHERE  type = 'SQLStats'       AND name = 'SlowLog' ORDER  BY create_time LIMIT  1000, 10;

Okay, maybe more than 90% of the DBA to resolve the problem so far. But when the LIMIT clause becomes "LIMIT 1000000,10", programmers will still complain: I only get 10 records Why or slow?

To know the database does not know the article 1 million records from where to start, even if there is also need to calculate the index from scratch again. This performance problems, in most cases is a lazy programmer.

Browse the page data in the front end, or a large batch of data to export other scenes, the maximum value may be as a previous parameter as a query. SQL redesigned as follows:

image.png

The basic query time fixed in the new design, not with the amount of data grows and changes.

2, implicit conversion

SQL statement query variables and fields defined type mismatch is another common mistake. For example, the following statement:

mysql> explain extended SELECT *      
          > FROM  my_balance b      
          > WHERE  b.bpn = 14000000123      
          >                AND b.isverified IS NULL ;
mysql> show warnings;
| Warning | 1739 | Cannot use ref access on index'bpn'due totypeor collation conversion on field'bpn'

Wherein bpn defined fields as varchar (20), MySQL, then the strategy comparison string after converting to digital. Function applied to the table fields, indices failure.

The above application framework may be filled automatically parameter rather than the programmer's intent. Now a lot of very complicated application framework, easy to use but also be careful it might give yourself digging.

3, the association update, delete

Although MySQL5.6 the introduction of physical and chemical properties, but it currently only requires special attention for optimizing the query statement. For the need to manually update or delete rewritten JOIN.

For example, the following UPDATE statement, MySQL is the actual implementation cycles / nested subqueries (DEPENDENT SUBQUERY), the execution time can be imagined.

image.png

Implementation plan:

+----+--------------------+-------+-------+---------------+---------+---------+-------+------+-----------------------------------------------------+
| id | select_type        | table |type| possible_keys | key    | key_len | ref  | rows | Extra                                              |
+----+--------------------+-------+-------+---------------+---------+---------+-------+------+-----------------------------------------------------+
| 1  | PRIMARY            | o    | index |              | PRIMARY | 8      |      | 24  | Usingwhere; Using temporary                        |
| 2  | DEPENDENT SUBQUERY |      |      |              |        |        |      |      | Impossible WHERE noticed after reading const tables |
| 3  | DERIVED            | o    | ref  | idx_2,idx_5  | idx_5  | 8      | const | 1    | Usingwhere; Using filesort                        |
+----+--------------------+-------+-------+---------------+---------+---------+-------+------+-----------------------------------------------------+

重写为 JOIN 之后,子查询的选择模式从 DEPENDENT SUBQUERY 变成 DERIVED,执行速度大大加快,从7秒降低到2毫秒。

image.png

执行计划简化为:

+----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------------------------------+
| id | select_type | table |type| possible_keys | key  | key_len | ref  | rows | Extra                                              |
+----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------------------------------+
| 1  | PRIMARY    |      |      |              |      |        |      |      | Impossible WHERE noticed after reading const tables |
| 2  | DERIVED    | o    | ref  | idx_2,idx_5  | idx_5 | 8      | const | 1    | Usingwhere; Using filesort                        |
+----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------------------------------+

4、混合排序

MySQL 不能利用索引进行混合排序。但在某些场景,还是有机会使用特殊方法提升性能的。

image.png

执行计划显示为全表扫描:

+----+-------------+-------+--------+-------------+---------+---------+---------------+---------+-+
| id | select_type | table |type| possible_keys    | key    | key_len | ref      | rows    | Extra    
+----+-------------+-------+--------+-------------+---------+---------+---------------+---------+-+
|  1 | SIMPLE      | a    | ALL    | idx_orderid | NULL    | NULL    | NULL    | 1967647 | Using filesort |
|  1 | SIMPLE      | o    | eq_ref | PRIMARY    | PRIMARY | 122    | a.orderid |      1 | NULL          |
+----+-------------+-------+--------+---------+---------+---------+-----------------+---------+-+

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

image.png

5、EXISTS语句

MySQL 对待 EXISTS 子句时,仍然采用嵌套子查询的执行方式。如下面的 SQL 语句:

image.png

执行计划为:

+----+--------------------+-------+------+-----+------------------------------------------+---------+-------+---------+ -----+
| id | select_type        | table |type| possible_keys    | key  | key_len | ref  | rows    | Extra  |
+----+--------------------+-------+------+ -----+------------------------------------------+---------+-------+---------+ -----+
|  1 | PRIMARY            | n    | ALL  |  | NULL    | NULL    | NULL  | 1086041 | Usingwhere|
|  1 | PRIMARY            | sra  | ref  |  | idx_user_id | 123    | const |      1 | Usingwhere|
|  2 | DEPENDENT SUBQUERY | m    | ref  |  | idx_message_info  | 122    | const |      1 | Using index condition; Usingwhere|
+----+--------------------+-------+------+ -----+------------------------------------------+---------+----

去掉 exists 更改为 join,能够避免嵌套子查询,将执行时间从1.93秒降低为1毫秒。

image.png

新的执行计划:

+----+-------------+-------+--------+ -----+------------------------------------------+---------+ -----+------+ -----+
| 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 | Usingwhere|
|  1 | SIMPLE      | sra  | ref    | | idx_user_id | 123    | const    |    1 | Usingwhere|
+----+-------------+-------+--------+ -----+------------------------------------------+---------+ -----+

6、条件下推

外部查询条件不能够下推到复杂的视图或子查询的情况有:

聚合子查询;

含有 LIMIT 的子查询;

UNION 或 UNION ALL 子查询;

输出字段中的子查询;

如下面的语句,从执行计划可以看出其条件作用于聚合子查询之后:

image.png

确定从语义上查询条件可以直接下推后,重写如下:

image.png

执行计划变为:

+----+-------------+-----------+------+---------------+-------+---------+-------+------+--------------------+
| id | select_type | table |type| possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+-------+---------+-------+------+--------------------+
| 1 | SIMPLE | operation | ref | idx_4 | idx_4 | 514 | const | 1 | Usingwhere; Using index |
+----+-------------+-----------+------+---------------+-------+---------+-------+------+--------------------+

7、提前缩小范围

先上初始 SQL 语句:

image.png

该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 | Usingwhere; 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 | Usingwhere; Using join buffer (Block Nested Loop) |
+----+-------------+-------+--------+---------------+---------+---------+-----------------+--------+----------------------------------------------------+

由于最后 WHERE 条件以及排序均针对最左主表,因此可以先对 my_order 排序提前缩小数据量再做左连接。SQL 重写后如下,执行时间缩小为1毫秒左右。

image.png

再检查执行计划:子查询物化后(select_type=DERIVED)参与 JOIN。虽然估算行扫描仍然为90万,但是利用了索引以及 LIMIT 子句后,实际执行时间变得很小。复制代码

+----+-------------+------------+--------+---------------+---------+---------+-------+--------+----------------------------------------------------+
| id | select_type | table      |type| possible_keys | key    | key_len | ref  | rows  | Extra                                              |
+----+-------------+------------+--------+---------------+---------+---------+-------+--------+----------------------------------------------------+
|  1 | PRIMARY    | | ALL    | NULL          | NULL    | NULL    | NULL  |    15 | Using temporary; Using filesort                    |
|  1 | PRIMARY    | u          | eq_ref | PRIMARY      | PRIMARY | 4      | o.uid |      1 | NULL                                              |
|  1 | PRIMARY    | p          | ALL    | PRIMARY      | NULL    | NULL    | NULL  |      6 | Usingwhere; Using join buffer (Block Nested Loop) |
|  2 | DERIVED    | o          | index  | NULL          | idx_1  | 5      | NULL  | 909112 | Usingwhere|
+----+-------------+------------+--------+---------------+---------+---------+-------+--------+----------------------------------------------------+

8, the intermediate result sets pushdown

Examples (left main table join in the priority action query) look at the following has been initially optimized:

image.png

So the statement that there are other problems? C is not difficult to see the whole table subqueries aggregate queries, in a particularly large number of table situation will lead to decreased performance of the entire statement.

In fact, for subqueries c, left the final outcome of the connection data can be set only interested in the main table and resourceid can match. Therefore, we can rewrite the following statements, execution time decreased from the original 2 milliseconds to 2 seconds.

image.png

But a sub-query appears more than once in our SQL statement. Such an approach not only additional costs, but also makes the entire statement of significant complexity. Rewrite again using the WITH statement:

image.png

to sum up

Database compiler generates the execution plan, determine the actual implementation of SQL. But the compiler just try the service, the compiler of all the databases are not perfect.

Most of the above-mentioned scene, there are performance problems in other databases. Learn database compiler features, its weaknesses in order to avoid regulation, to write high-performance SQL statement.

Programmers in the design of the data model and write SQL statements, thought or consciousness algorithm should be brought in.

Write complex SQL statements to develop the habit of using the WITH statement. Concise and clear thinking of SQL statements can also reduce the burden on the database.


Guess you like

Origin blog.51cto.com/14453419/2422359