這是學習筆記的第 1978 篇文章
今天優化了幾個SQL問題,拿出來兩個做下總結和分享。
第一條SQL如下,內容做了刪減。
SELECT p.*, m.uid, m.username, m.groupid, ....m.email, m.gender, m.showemail, m.invisible
FROM cdb_posts p
LEFT JOIN cdb_members m ON m.uid=p.authorid
LEFT JOIN cdb_memberfields mf ON mf.uid=m.uid
WHERE p.tid='xxxxx' AND p.invisible='0' ORDER BY first DESC,dateline DESC LIMIT 13250, 50
這條語句的執行效率根據監控,平均時間在9秒,但是在測試的時候,時間執行時間遠遠大于9秒,我們就暫且按照9秒來估算時間成本吧。
cdb_posts表的數據有3000多萬,另外兩個表cdb_members,cdb_memberfields的數據量也不小,量級在七百萬。
其中索引分布在如下的字段中:
- 索引字段:cdb_posts.authorid,tid 數據量:3000多萬
- 索引字段:cdb_members.uid 數據量:700多萬
- 索引字段:cdb_memberfields.uid 數據量:3000多萬
對于這樣一個SQL,按照目前的執行情況,基于LEFT JOIN,肯定是有一個表要“全量”了。
所以整個SQL的關注目標先在于where子句:
p.tid='xxxxx' AND p.invisible='0'
根據測試,這個數據量也相對小一些:
>>SELECT count(*)
-> FROM cdb_posts p
-> LEFT JOIN discuz.cdb_members m ON m.uid=p.authorid
-> WHERE p.tid='6297759' AND p.invisible='0' ;
+----------+
| count(*) |
+----------+
| 29625 |
+----------+
1 row in set (7.27 sec)
所以我們后續的測試會以這個數據作為基礎,執行計劃如下:
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: p
type: ref
possible_keys: displayorder,idx_tid_fir_authorid,idx_invisible
key: displayorder
key_len: 4
ref: const,const
rows: 59148
Extra: Using where; Using filesort
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: m
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: test.p.authorid
rows: 1
Extra:
*************************** 3. row ***************************
id: 1
select_type: SIMPLE
table: mf
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: test.m.uid
rows: 1
Extra:
3 rows in set (0.00 sec)
從執行計劃來看,瓶頸點就在于第1部分了,整個SQL的執行路徑類似于下面的形式: