簡體   English   中英

優化這段MYSQL代碼以縮短執行時間

[英]Optimizing this piece of MYSQL Code for better execution time

這段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://explainextended.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                     |
+----+-------------+------------+--------+-------------------------------+---------+---------+------+--------+---------------------------------+

查看顯示最里面的語句使用PRIMARY索引的key列。 我稍微修改了您的查詢,以便值類型兼容:

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行-我想這不是您要的。 現在在所示的情況下(inner語句中的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        |
+----+-------------+------------+--------+-------------------------------+-----------------------+---------+------+-------+---------------------------------+

同樣,我們只掃描索引頁面。

您可以將查詢編寫為:

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

但是,這不會提高性能。 MySQL必須讀取數據頁以獲取具有正確值的行。

您還可以使用其他索引:(值),(值,id)和(id,值)。 這些將對性能產生不同的影響。

第一個將使用索引來滿足WHERE子句,然后基本上忽略索引的“ id”部分。 如果value > 100具有高度選擇性(例如,少於1%的記錄滿足此條件),這將提高性能。

第二個可能有幫助。 老實說,我不知道MySQL是否將從索引中讀取ID,然后進行排序。 或者,如果它將讀取原始數據。 如果是第一個,這將有所幫助。

第三個可能是最好的選擇。 我認為MySQL將讀取索引以查找匹配的值,然后將索引用於排序和限制。 我的意思是,應該,但是我不是100%肯定引擎會真正做到這一點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM