[英]MySQL performance for version 5.7 vs. 5.6
我注意到我不確定如何處理特定的性能問題。
我正在將Web應用程序從一台服務器遷移到具有非常相似規范的另一台服務器。 通常,新服務器的性能要優於舊服務器。
舊服務器正在運行MySQL 5.6.35
新服務器正在運行MySQL 5.7.17
新服務器和舊服務器實際上都具有相同的MySQL配置。 新服務器和舊服務器都運行完全相同的完全相同的數據庫。
有問題的Web應用程序是Magento 1.9.3.2。
在Magento中,以下函數Mage_Catalog_Model_Category::getChildrenCategories()
旨在列出給定類別的所有直接子類別。
就我而言,此函數最終會涉及以下查詢:
SELECT `main_table`.`entity_id`
, main_table.`name`
, main_table.`path`
, `main_table`.`is_active`
, `main_table`.`is_anchor`
, `url_rewrite`.`request_path`
FROM `catalog_category_flat_store_1` AS `main_table`
LEFT JOIN `core_url_rewrite` AS `url_rewrite`
ON url_rewrite.category_id=main_table.entity_id
AND url_rewrite.is_system=1
AND url_rewrite.store_id = 1
AND url_rewrite.id_path LIKE 'category/%'
WHERE (main_table.include_in_menu = '1')
AND (main_table.is_active = '1')
AND (main_table.path LIKE '1/494/%')
AND (`level` <= 2)
ORDER BY `main_table`.`position` ASC;
盡管此查詢的結構對於任何Magento安裝都是相同的,但是在Magento安裝到Magento安裝與該功能所查看的類別之間的值顯然會略有差異。
我的catalog_category_flat_store_1
表有214行。
我的url_rewrite
表有1,734,316行。
直接在MySQL中單獨執行時,此查詢在MySQL版本之間的執行方式有很大不同。
我正在使用SQLyog來分析此查詢。
在MySQL 5.6中,以上查詢將在0.04秒內執行。 該查詢的配置文件如下所示: https : //codepen.io/Petce/full/JNKEpy/
在MySQL 5.7中,以上查詢在1.952秒內執行。 該查詢的配置文件如下所示: https : //codepen.io/Petce/full/gWMgKZ/
如您所見,幾乎完全相同的設置上的相同查詢實際上要慢2秒,我不確定原因。
由於某些原因,MySQL 5.7不想使用表索引來幫助生成結果集。
任何有更多經驗/知識的人都可以解釋這里發生了什么以及如何解決它?
我認為該問題與MYSQL 5.7優化器的工作方式有關。 出於某種原因,似乎認為全表掃描是必經之路。 我可以通過將max_seeks_for_key設置得非常低(例如100)或將range_optimizer_max_mem_size設置得非常低以強制其發出警告來大大提高查詢性能。
進行這兩種操作都會使查詢速度降低近10倍,降至0.2秒,但是,這要比在0.04秒內執行的MySQL 5.6慢很多,而且我認為這都不是一個好主意,因為我不是確定是否還會有其他影響。
修改查詢也是非常困難的,因為它是由Magento框架生成的,並且需要自定義Magento代碼庫,我想避免這種情況。 我也不確定這是否是唯一的查詢。
我已經為我的MySQL安裝提供了次要版本。 我現在正在嘗試將MySQL 5.7.17更新到5.7.18(最新版本),以查看性能是否有任何更新。
升級到MySQL 5.7.18之后,我看不到任何改善。 為了使系統恢復到穩定的高性能狀態,我們決定降級到MySQL 5.6.30。 降級后,我們看到了即時的改進。
以上查詢是在MySQL 5.6.30中在0.036秒內在NEW服務器上執行的。
哇! 這是我第一次從剖析中看到有用的東西。 動態創建索引是Oracle的一項新的優化功能。 但這似乎不是針對此案的最佳計划。
首先,我建議您在http://bugs.mysql.com上提交一個錯誤-他們不喜歡回歸,尤其是這種令人討厭的回歸。 如果可能,請提供EXPLAIN FORMAT=JSON SELECT...
和“ Optimizer trace”。 (我不接受調整模糊的可調參數作為可接受的答案,但是感謝您發現它們。)
回到幫助您...
LEFT
,請不要使用它。 當“正確的”表中沒有匹配的行時,它將返回NULLs
。 你會發生這種情況嗎? SHOW CREATE TABLE
。 同時,我猜您沒有INDEX(include_in_menu, is_active, path)
。 前兩個可以任意順序排列。 path
必須是最后一條。 INDEX(category_id, is_system, store_id, id_path)
和id_path
。 (注意:這甚至保留了LEFT
的語義。)
SELECT `main_table`.`entity_id` , main_table.`name` , main_table.`path` ,
`main_table`.`is_active` , `main_table`.`is_anchor` ,
( SELECT `request_path`
FROM url_rewrite
WHERE url_rewrite.category_id=main_table.entity_id
AND url_rewrite.is_system = 1
AND url_rewrite.store_id = 1
AND url_rewrite.id_path LIKE 'category/%'
) as request_path
FROM `catalog_category_flat_store_1` AS `main_table`
WHERE (main_table.include_in_menu = '1')
AND (main_table.is_active = '1')
AND (main_table.path like '1/494/%')
AND (`level` <= 2)
ORDER BY `main_table`.`position` ASC
LIMIT 0, 1000
(建議的索引也適用於此。)
這不是回答@Nigel Ren的唯一答案
在這里您可以看到LIKE也使用索引。
mysql> SELECT *
-> FROM testdb
-> WHERE
-> vals LIKE 'text%';
+----+---------------------------------------+
| id | vals |
+----+---------------------------------------+
| 3 | text for line number 3 |
| 1 | textline 1 we rqwe rq wer qwer q wer |
| 2 | textline 2 asdf asd fas f asf wer 3 |
+----+---------------------------------------+
3 rows in set (0,00 sec)
mysql> EXPLAIN
-> SELECT *
-> FROM testdb
-> WHERE
-> vals LIKE 'text%';
+----+-------------+--------+------------+-------+---------------+------+---------+------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+-------+---------------+------+---------+------+------+----------+--------------------------+
| 1 | SIMPLE | testdb | NULL | range | vals | vals | 515 | NULL | 3 | 100.00 | Using where; Using index |
+----+-------------+--------+------------+-------+---------------+------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0,01 sec)
mysql>
用LEFT()采樣
mysql> SELECT *
-> FROM testdb
-> WHERE
-> LEFT(vals,4) = 'text';
+----+---------------------------------------+
| id | vals |
+----+---------------------------------------+
| 3 | text for line number 3 |
| 1 | textline 1 we rqwe rq wer qwer q wer |
| 2 | textline 2 asdf asd fas f asf wer 3 |
+----+---------------------------------------+
3 rows in set (0,01 sec)
mysql> EXPLAIN
-> SELECT *
-> FROM testdb
-> WHERE
-> LEFT(vals,4) = 'text';
+----+-------------+--------+------------+-------+---------------+------+---------+------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+-------+---------------+------+---------+------+------+----------+--------------------------+
| 1 | SIMPLE | testdb | NULL | index | NULL | vals | 515 | NULL | 5 | 100.00 | Using where; Using index |
+----+-------------+--------+------------+-------+---------------+------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0,01 sec)
mysql>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.