最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

通過MySQL優(yōu)化Discuz!的熱帖翻頁的技巧

 更新時間:2015年05月07日 16:43:24   作者:葉金榮  
這篇文章主要介紹了通過MySQL優(yōu)化Discuz!的熱帖翻頁的技巧,包括更新索引來降低服務器負載等方面,需要的朋友可以參考下

寫在前面:discuz!作為首屈一指的社區(qū)系統(tǒng),為廣大站長提供了一站式網站解決方案,而且是開源的(雖然部分代碼是加密的),它為這個垂直領域的行業(yè)發(fā)展作出了巨大貢獻。盡管如此,discuz!系統(tǒng)源碼中,還是或多或少有些坑。其中最著名的就是默認采用MyISAM引擎,以及基于MyISAM引擎的搶樓功能,session表采用memory引擎等,可以參考后面幾篇歷史文章。本次我們要說說discuz!在應對熱們帖子翻頁邏輯功能中的另一個問題。

在我們的環(huán)境中,使用的是 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執(zhí)行的代價是:

-- 根據索引訪問行記錄次數(shù),總體而言算是比較好的狀態(tài)

| Handler_read_key   | 16  |

-- 根據索引順序訪問下一行記錄的次數(shù),通常是因為根據索引的范圍掃描,或者全索引掃描,總體而言也算是比較好的狀態(tài)

| Handler_read_next   | 329881 |

-- 按照一定順序讀取行記錄的總次數(shù)。如果需要對結果進行排序,該值通常會比較大。當發(fā)生全表掃描或者多表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執(zhí)行的代價則變成了(可以看到Handler_read_key、Handler_read_rnd大了很多):

| Handler_read_key           | 129876 | -- 因為前面需要跳過很多行記錄
| Handler_read_next          | 329881 | -- 同上
| Handler_read_rnd           | 129875 | -- 因為需要先對很大一個結果集進行排序

可見,遇到熱帖時,這個SQL的代價會非常高。如果該熱帖被大量的訪問歷史回復,或者被搜素引擎一直反復請求并且歷史回復頁時,很容易把數(shù)據庫服務器直接壓垮。

小結:這個SQL不能利用 `displayorder` 索引排序的原因是,索引的第二個列 `invisible` 采用范圍查詢(RANGE),導致沒辦法繼續(xù)利用聯(lián)合索引完成對 `dateline` 字段的排序需求(而如果是 WHERE tid =? AND invisible IN(?, ?) AND dateline =? 這種情況下是完全可以用到整個聯(lián)合索引的,注意下二者的區(qū)別)。

知道了這個原因,相應的優(yōu)化解決辦法也就清晰了:
創(chuàng)建一個新的索引 idx_tid_dateline,它只包括 tid、dateline 兩個列即可(根據其他索引的統(tǒng)計信息,item_type 和 item_id 的基數(shù)太低,所以沒包含在聯(lián)合索引中。當然了,也可以考慮一并加上)。

我們再來看下采用新的索引后的執(zhí)行計劃:

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

對比下如果建議優(yōu)化器使用新索引的話,其執(zhí)行計劃是怎樣的:

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

可以看到,因為查詢優(yōu)化器認為后者需要掃描的行數(shù)遠比前者多了11萬多,因此認為前者效率更高。

事實上,在這個例子里,排序的代價更高,因此我們要優(yōu)先消除排序,所以應該強制使用新的索引,也就是采用后面的執(zhí)行計劃,在相應的程序中指定索引。

最后,我們來看下熱帖翻到很老的歷史回復時,兩個執(zhí)行計劃分別的profiling統(tǒng)計信息對比:

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 |

可以看到,效率有了一定提高,不過不是很明顯,因為確實需要掃描的數(shù)據量更大,所以 Sending data 階段耗時更多。

這時候,我們可以再參考之前的一個優(yōu)化方案:[MySQL優(yōu)化案例]系列 — 分頁優(yōu)化

然后可以將這個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 統(tǒng)計信息:

| 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倍以上,還是挺不錯的。

最后說明下,這個問題只會在熱帖翻頁時才會出現(xiàn),一般只有1,2頁回復的帖子如果還采用原來的執(zhí)行計劃,也沒什么問題。

因此,建議discuz!官方修改或增加下新索引,并且在代碼中判斷是否熱帖翻頁,是的話,就強制使用新的索引,以避免性能問題。

相關文章

  • Mysql分析設計表主鍵為何不用uuid

    Mysql分析設計表主鍵為何不用uuid

    在mysql中設計表的時候,mysql官方推薦不要使用uuid或者不連續(xù)不重復的雪花id(long形且唯一),而是推薦連續(xù)自增的主鍵id,官方的推薦是auto_increment,那么為什么不建議采用uuid,使用uuid究竟有什么壞處?本篇博客我們就來分析這個問題,探討一下內部的原因
    2022-03-03
  • MYSQL必知必會讀書筆記第八章之使用通配符進行過濾

    MYSQL必知必會讀書筆記第八章之使用通配符進行過濾

    這篇文章主要介紹了MYSQL必知必會讀書筆記第八章之使用通配符進行過濾的相關資料,需要的朋友可以參考下
    2016-05-05
  • MySQL查找NULL值的全面指南

    MySQL查找NULL值的全面指南

    在數(shù)據庫中,NULL 值表示缺失或未知的數(shù)據,在 MySQL 中,我們可以使用特定的查詢語句來查找包含 NULL 值的數(shù)據,本文將詳細介紹如何在 MySQL 中查找 NULL 值,并提供相關實例和代碼片段,需要的朋友可以參考下
    2024-05-05
  • 手把手教你用SQL獲取年、月、周幾、日、時

    手把手教你用SQL獲取年、月、周幾、日、時

    時間處理是我們日常開發(fā)中經常遇到的需求,下面這篇文章主要給大家介紹了關于如何用SQL獲取年、月、周幾、日、時的相關資料,文中通過圖文介紹的非常詳細,需要的朋友可以參考下
    2022-12-12
  • MySQL數(shù)據導入導出的三種辦法總結

    MySQL數(shù)據導入導出的三種辦法總結

    當我們需要切換數(shù)據庫或備份數(shù)據時,導入和導出數(shù)據庫是一個常見的操作,下面這篇文章主要給大家介紹了關于MySQL數(shù)據導入導出的三種辦法,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-05-05
  • MySQL表鎖定問題的原因、檢測與解決方案

    MySQL表鎖定問題的原因、檢測與解決方案

    在數(shù)據庫管理系統(tǒng)中,鎖是保證數(shù)據一致性和事務隔離性的重要機制,然而,鎖的使用也可能導致性能問題,尤其是在高并發(fā)場景下,表鎖定(Table Locking)可能會成為系統(tǒng)的瓶頸,本文將深入探討MySQL中表鎖定的原因、如何檢測表鎖定問題,并提供有效的解決方案
    2025-01-01
  • linux環(huán)境下配置mysql5.6支持IPV6連接的方法

    linux環(huán)境下配置mysql5.6支持IPV6連接的方法

    本文主要介紹在linux系統(tǒng)下,如何配置mysql支持IPV6的連接,本文圖文并茂給大家介紹的非常詳細,具有參考借鑒價值,需要的朋友參考下吧
    2018-01-01
  • Oracle和MySQL中生成32位uuid的方法舉例(國產達夢同Oracle)

    Oracle和MySQL中生成32位uuid的方法舉例(國產達夢同Oracle)

    近日遇到朋友問及如何生成UUID,UUID是通用唯一識別碼(Universally Unique Identifier)方法,這里給大家總結下,這篇文章主要給大家介紹了關于Oracle和MySQL中生成32位uuid的方法,需要的朋友可以參考下
    2023-08-08
  • 巧用mysql提示符prompt清晰管理數(shù)據庫的方法

    巧用mysql提示符prompt清晰管理數(shù)據庫的方法

    隨著管理mysql服務器越來越多,同樣的mysql>的提示符有可能會讓你輸入錯誤的命令到錯誤的數(shù)據庫,這時候需要巧用mysql的提示符,這是我的提示符root@localhost(mysql) 08:55:21> 用prompt命令實現(xiàn)(適用于windows和linux環(huán)境)
    2009-08-08
  • Can''t connect to local MySQL through socket ''/tmp/mysql.sock''解決方法

    Can''t connect to local MySQL through socket ''/tmp/mysql.so

    今天小編就為大家分享一篇關于Can't connect to local MySQL through socket '/tmp/mysql.sock'解決方法,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03

最新評論

五台县| 孟津县| 滦南县| 梅河口市| 鄢陵县| 开封市| 南昌县| 临汾市| 体育| 凌海市| 玉龙| 淳化县| 张掖市| 拉萨市| 冕宁县| 东安县| 秦皇岛市| 贡嘎县| 望城县| 赣州市| 镇沅| 罗定市| 定州市| 山东省| 迁西县| 襄城县| 永胜县| 太仆寺旗| 自治县| 化德县| 蒙阴县| 资中县| SHOW| 鹤岗市| 曲阜市| 澄迈县| 富蕴县| 运城市| 长海县| 徐汇区| 镇江市|