mysql - 优化这段 MYSQL 代码以获得更好的执行时间

标签 mysql sql database performance

这段mysql代码

SELECT  id, value, LENGTH(stuffing)
FROM  t_limit ORDER BY id LIMIT 150000, 10

可以通过像这样重写来优化以获得更好的性能

注意:表在 Id 上有索引

SELECT  l.id, value, LENGTH(stuffing)
FROM    (
    SELECT  id
    FROM    t_limit
    ORDER BY
            id
    LIMIT 150000, 10
    ) o
JOIN    t_limit l
ON      l.id = o.id
ORDER BY
    l.id

引用:http://explainextend.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/

现在如何以类似的方式优化这段代码

SELECT  id, value, LENGTH(stuffing)
FROM  t_limit where value>100 ORDER BY id LIMIT 150000, 10

最佳答案

上述文章中提出的优化背后的基本思想是仅查询索引页而不接触数据页。如果查看非优化查询的查询计划:

SELECT  id, value, LENGTH(stuffing) AS len
FROM    t_limit
ORDER BY
        id
LIMIT 150000, 10

这将是:

+----+-------------+---------+------+---------------+------+---------+------+--------+----------------+
| id | select_type | table   | type | possible_keys | key  | key_len | ref  | rows   | Extra
+----+-------------+---------+------+---------------+------+---------+------+--------+----------------+
|  1 | SIMPLE      | t_limit | ALL  | NULL          | NULL | NULL    | NULL | 200000 | Using filesort |
+----+-------------+---------+------+---------------+------+---------+------+--------+----------------+

所以这是一个简单的表扫描。通过子查询优化,我们得到:

+----+-------------+------------+--------+-------------------------------+---------+---------+------+--------+---------------------------------+
| id | select_type | table      | type   | possible_keys                 | key     | key_len | ref  | rows   | Extra                           |
+----+-------------+------------+--------+-------------------------------+---------+---------+------+--------+---------------------------------+
|  1 | PRIMARY     | <derived2> | ALL    | NULL                          | NULL    | NULL    | NULL |     10 | Using temporary; Using filesort |
|  1 | PRIMARY     | l          | eq_ref | PRIMARY                       | PRIMARY | 4       | o.id |      1 |                                 |
|  2 | DERIVED     | t_limit    | index  | NULL                          | PRIMARY | 4       | NULL | 150010 | Using index                     |
+----+-------------+------------+--------+-------------------------------+---------+---------+------+--------+---------------------------------+

查看key列,它显示最里面的语句使用了PRIMARY索引。我稍微修改了您的查询,以便值类型兼容:

SELECT  l.id, value, LENGTH(stuffing) AS len
FROM    (
        SELECT  id
        FROM    t_limit
        where value like 'Value 1%'
        ORDER BY
                id
        LIMIT 30000, 10
        ) o
JOIN    t_limit l
ON      l.id = o.id
ORDER BY
        l.id

您需要考虑 where 条件的作用。如果您将其放入外部查询中,您将仅过滤从内部查询返回的 10 行 - 我认为这不是您所要求的。现在,在所呈现的情况下(内部语句中的 where 条件),您将最终进行表扫描,因为没有索引可以满足您的查询:

+----+-------------+------------+--------+---------------+---------+---------+------+--------+--------------------------------+
| id | select_type | table      | type   | possible_keys | key     | key_len | ref  | rows   | Extra                           |
+----+-------------+------------+--------+---------------+---------+---------+------+--------+---------------------------------+
|  1 | PRIMARY     | <derived2> | ALL    | NULL          | NULL    | NULL    | NULL |     10 | Using temporary; Using filesort |
|  1 | PRIMARY     | l          | eq_ref | PRIMARY       | PRIMARY | 4       | o.id |      1 |                                 |
|  2 | DERIVED     | t_limit    | ALL    | NULL          | NULL    | NULL    | NULL | 200000 | Using filesort                  |
+----+-------------+------------+--------+---------------+---------+---------+------+--------+---------------------------------+

要从博客文章中介绍的相同优化中获益,您需要一个额外的非聚集索引,例如。

create index NCIX_t_limit_id_value on t_limit(id, value)

现在,当您运行上述查询时,计划将是:

+----+-------------+------------+--------+-------------------------------+-----------------------+---------+------+-------+---------------------------------+
| id | select_type | table      | type   | possible_keys                 | key                   | key_len | ref  | rows  | Extra                           |
+----+-------------+------------+--------+-------------------------------+-----------------------+---------+------+-------+---------------------------------+
|  1 | PRIMARY     | <derived2> | ALL    | NULL                          | NULL                  | NULL    | NULL |    10 | Using temporary; Using filesort |
|  1 | PRIMARY     | l          | eq_ref | PRIMARY,NCIX_t_limit_id_value | PRIMARY               | 4       | o.id |     1 |                                 |
|  2 | DERIVED     | t_limit    | index  | NULL                          | NCIX_t_limit_id_value | 66      | NULL | 30010 | Using where; Using index        |
+----+-------------+------------+--------+-------------------------------+-----------------------+---------+------+-------+---------------------------------+

再说一遍,我们只扫描索引页。

关于mysql - 优化这段 MYSQL 代码以获得更好的执行时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12605137/

相关文章:

php - 尽管代码相同,但在一台服务器上出现 SQL 错误,但在另一台服务器上却没有

mysql - 将 mysql 查找表转换为 mongodb 的最佳实践是什么

MySQL 连接语法未知列

mysql - 如何将多个 Rails SQL 查询合并到 Rails 中的单个查询中?

c# - 来自 textBox 的值没有被插入到数据库中

mysql - F# 连接到在线 MySQL DB 执行查询

php - OSCommerce tep_db_input 与 tep_db_prepare_input

mysql - SQL从特定日期范围开始进行不同计数?

php - 连接 2 个表无法正常工作

mysql - 如果我似乎需要将一个表的列名存储在另一个表中,我是否应该重新考虑我的数据库设计?