經由過程MySQL優化Discuz!的熱帖翻頁的技能。本站提示廣大學習愛好者:(經由過程MySQL優化Discuz!的熱帖翻頁的技能)文章只能為提供參考,不一定能成為您想要的結果。以下是經由過程MySQL優化Discuz!的熱帖翻頁的技能正文
寫在後面:discuz!作為數一數二的社區體系,為寬大站長供給了一站式網站處理計劃,並且是開源的(固然部門代碼是加密的),它為這個垂直范疇的行業成長作出了偉大進獻。雖然如斯,discuz!體系源碼中,照樣或多或少有些坑。個中最有名的就是默許采取MyISAM引擎,和基於MyISAM引擎的搶樓功效,session表采取memory引擎等,可以參考前面幾篇汗青文章。本次我們要說說discuz!在應對熱們帖子翻頁邏輯功效中的另外一個成績。
在我們的情況中,應用的是 MySQL-5.6.6 版本。
在檢查帖子並翻頁進程中,會發生相似上面如許的SQL:
mysql> desc SELECT * FROM pre_forum_post WHERE
tid=8201301 AND `invisible` IN('0','-2') ORDER BY dateline DESC LIMIT 15\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: pre_forum_post
type: ref
possible_keys: tid,displayorder,first
key: displayorder
key_len: 3
ref: const
rows: 593371
Extra: Using index condition; Using where; Using filesort
這個SQL履行的價值是:
-- 依據索引拜訪行記載次數,整體而言算是比擬好的狀況
| Handler_read_key | 16 |
-- 依據索引次序拜訪下一行記載的次數,平日是由於依據索引的規模掃描,或許全索引掃描,整體而言也算是比擬好的狀況
| Handler_read_next | 329881 |
-- 依照必定次序讀取行記載的總次數。假如須要對成果停止排序,該值平日會比擬年夜。當產生全表掃描或許多表join沒法應用索引時,該值也會比擬年夜
| Handler_read_rnd | 15 |
而當碰到熱帖須要往後翻許多頁時,例如:
mysql> desc SELECT * FROM pre_forum_post WHERE
tid=8201301 AND `invisible` IN('0','-2') ORDER BY dateline LIMIT 129860, 15\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: pre_forum_post
type: ref
possible_keys: displayorder
key: displayorder
key_len: 3
ref: const
rows: 593371
Extra: Using where; Using filesort
這個SQL履行的價值則釀成了(可以看到Handler_read_key、Handler_read_rnd年夜了許多):
| Handler_read_key | 129876 | -- 由於後面須要跳過許多行記載
| Handler_read_next | 329881 | -- 同上
| Handler_read_rnd | 129875 | -- 由於須要先對很年夜一個成果集停止排序
可見,碰到熱帖時,這個SQL的價值會異常高。假如該熱帖被年夜量的拜訪汗青答復,或許被搜素引擎一向重復要求而且汗青答復頁時,很輕易把數據庫辦事器直接壓垮。
小結:這個SQL不克不及應用 `displayorder` 索引排序的緣由是,索引的第二個列 `invisible` 采取規模查詢(RANGE),招致沒方法持續應用結合索引完成對 `dateline` 字段的排序需求(而假如是 WHERE tid =? AND invisible IN(?, ?) AND dateline =? 這類情形下是完整可以用到全部結合索引的,留意下兩者的差別)。
曉得了這個緣由,響應的優化處理方法也就清楚了:
創立一個新的索引 idx_tid_dateline,它只包含 tid、dateline 兩個列便可(依據其他索引的統計信息,item_type 和 item_id 的基數太低,所以沒包括在結合索引中。固然了,也能夠斟酌一並加上)。
我們再來看下采取新的索引後的履行籌劃:
mysql> desc SELECT * FROM pre_forum_post WHERE
tid=8201301 AND `invisible` IN('0','-2') ORDER BY dateline LIMIT 15\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: pre_forum_post
type: ref
possible_keys: tid,displayorder,first,idx_tid_dateline
key: idx_tid_dateline
key_len: 3
ref: const
rows: 703892
Extra: Using where
可以看到,之前存在的 Using filesort 消逝了,可以經由過程索引直接完成排序了。
不外,假如該熱帖翻到較舊的汗青答復時,響應的SQL照樣不克不及應用新的索引:
mysql> desc SELECT * FROM pre_forum_post WHERE
tid=8201301 AND `invisible` IN('0','-2') ORDER BY dateline LIMIT 129860,15\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: pre_forum_post
type: ref
possible_keys: tid,displayorder,first,idx_tid_dateline
key: displayorder
key_len: 3
ref: const
rows: 593371
Extra: Using where; Using filesort
比較下假如建議優化器應用新索引的話,其履行籌劃是如何的:
mysql> desc SELECT * FROM pre_forum_post use index(idx_tid_dateline) WHERE
tid=8201301 AND `invisible` IN('0','-2') ORDER BY dateline LIMIT 129860,15\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: pre_forum_post
type: ref
possible_keys: idx_tid_dateline
key: idx_tid_dateline
key_len: 3
ref: const
rows: 703892
Extra: Using where
可以看到,由於查詢優化器以為後者須要掃描的行數遠比前者多了11萬多,是以以為前者效力更高。
現實上,在這個例子裡,排序的價值更高,是以我們要優先清除排序,所以應當強迫應用新的索引,也就是采取前面的履行籌劃,在響應的法式中指定索引。
最初,我們來看下熱帖翻到很老的汗青答復時,兩個履行籌劃分離的profiling統計信息比較:
1、采取舊索引(displayorder):
mysql> SELECT * FROM pre_forum_post WHERE
tid=8201301 AND `invisible` IN('0','-2') ORDER BY dateline LIMIT 129860,15;
#檢查profiling成果
| starting | 0.020203 |
| checking permissions | 0.000026 |
| Opening tables | 0.000036 |
| init | 0.000099 |
| System lock | 0.000092 |
| optimizing | 0.000038 |
| statistics | 0.000123 |
| preparing | 0.000043 |
| Sorting result | 0.000025 |
| executing | 0.000023 |
| Sending data | 0.000045 |
| Creating sort index | 0.941434 |
| end | 0.000077 |
| query end | 0.000044 |
| closing tables | 0.000038 |
| freeing items | 0.000056 |
| cleaning up | 0.000040 |
2、假如是采取新索引(idx_tid_dateline):
mysql> SELECT * FROM pre_forum_post use index(idx_tid_dateline) WHERE
tid=8201301 AND `invisible` IN('0','-2') ORDER BY dateline LIMIT 129860,15;
#比較檢查profiling成果
| starting | 0.000151 |
| checking permissions | 0.000033 |
| Opening tables | 0.000040 |
| init | 0.000105 |
| System lock | 0.000044 |
| optimizing | 0.000038 |
| statistics | 0.000188 |
| preparing | 0.000044 |
| Sorting result | 0.000024 |
| executing | 0.000023 |
| Sending data | 0.917035 |
| end | 0.000074 |
| query end | 0.000030 |
| closing tables | 0.000036 |
| freeing items | 0.000049 |
| cleaning up | 0.000032 |
可以看到,效力有了必定進步,不外不是很顯著,由於確切須要掃描的數據量更年夜,所以 Sending data 階段耗時更多。
這時候候,我們可以再參考之前的一個優化計劃:[MySQL優化案例]系列 — 分頁優化
然後可以將這個SQL改寫成上面如許:
mysql> EXPLAIN SELECT * FROM pre_forum_post t1 INNER JOIN (
SELECT id FROM pre_forum_post use index(idx_tid_dateline) WHERE
tid=8201301 AND `invisible` IN('0','-2') ORDER BY
dateline LIMIT 129860,15) t2
USING (id)\G
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table:
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 129875
Extra: NULL
*************************** 2. row ***************************
id: 1
select_type: PRIMARY
table: t1
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: t2.id
rows: 1
Extra: NULL
*************************** 3. row ***************************
id: 2
select_type: DERIVED
table: pre_forum_post
type: ref
possible_keys: idx_tid_dateline
key: idx_tid_dateline
key_len: 3
ref: const
rows: 703892
Extra: Using where
再看下這個SQL的 profiling 統計信息:
| starting | 0.000209 | | checking permissions | 0.000026 | | checking permissions | 0.000026 | | Opening tables | 0.000101 | | init | 0.000062 | | System lock | 0.000049 | | optimizing | 0.000025 | | optimizing | 0.000037 | | statistics | 0.000106 | | preparing | 0.000059 | | Sorting result | 0.000039 | | statistics | 0.000048 | | preparing | 0.000032 | | executing | 0.000036 | | Sending data | 0.000045 | | executing | 0.000023 | | Sending data | 0.225356 | | end | 0.000067 | | query end | 0.000028 | | closing tables | 0.000023 | | removing tmp table | 0.000029 | | closing tables | 0.000044 | | freeing items | 0.000048 | | cleaning up | 0.000037 |
可以看到,效力晉升了1倍以上,照樣挺不錯的。
最初解釋下,這個成績只會在熱帖翻頁時才會湧現,普通只要1,2頁答復的帖子假如還采取本來的履行籌劃,也沒甚麼成績。
是以,建議discuz!官方修正或增長下新索引,而且在代碼中斷定能否熱帖翻頁,是的話,就強迫應用新的索引,以免機能成績。