mysql千萬級表關聯優化


MYSQL一次千萬級連表查詢優化(一)

概述:

交代一下背景,這算是一次項目經驗吧,屬於公司一個已上線平台的功能,這算是離職人員挖下的坑,隨着數據越來越多,原本的SQL查詢變得越來越慢,用戶體驗特別差,因此SQL優化任務交到了我手上。 
這個SQL查詢關聯兩個數據表,一個是攻擊IP用戶表主要是記錄IP的信息,如第一次攻擊時間,地址,IP等等,一個是IP攻擊次數表主要是記錄每天IP攻擊次數。而需求是獲取某天攻擊IP信息和次數。(以下SQL語句測試均在測試服務器上上,正式服務器的性能好,查詢時間快不少。)

准備:

查看表的行數: 
這里寫圖片描述 
這里寫圖片描述 
未優化前SQL語句為:

SELECT attack_ip, country, province, city, line, info_update_time AS attack_time, sum( attack_count ) AS attack_times FROM `blacklist_attack_ip` INNER JOIN `blacklist_ip_count_date` ON `blacklist_attack_ip`.`attack_ip` = `blacklist_ip_count_date`.`ip` WHERE `attack_count` > 0 AND `date` BETWEEN '2017-10-13 00:00:00' AND '2017-10-13 23:59:59' GROUP BY `ip` LIMIT 10 OFFSET 1000

 

 

先EXPLAIN分析一下: 
這里寫圖片描述
這里看到索引是有的,但是IP攻擊次數表blacklist_ip_count_data也用上了臨時表。那么這SQL不優化直接第一次執行需要多久(這里強調第一次是因為MYSQL帶有緩存功能,執行過一次的同樣SQL,第二次會快很多。) 
這里寫圖片描述
實際查詢時間為300+秒,這完全不能接受呀,這還是沒有其他搜索條件下的。 
那么我們怎么優化呢,索引既然走了,我嘗試一下避免臨時表,這時我們先了解一下臨時表跟group by的使聯系:

查找了網上一些博客分析GROUP BY 與臨時表的關系 : 
  1. 如果GROUP BY 的列沒有索引,產生臨時表. 
  2. 如果GROUP BY時,SELECT的列不止GROUP BY列一個,並且GROUP BY的列不是主鍵 ,產生臨時表. 
  3. 如果GROUP BY的列有索引,ORDER BY的列沒索引.產生臨時表. 
  4. 如果GROUP BY的列和ORDER BY的列不一樣,即使都有索引也會產生臨時表. 
  5. 如果GROUP BY或ORDER BY的列不是來自JOIN語句第一個表.會產生臨時表. 
  6. 如果DISTINCT 和 ORDER BY的列沒有索引,產生臨時表.

仔細按照上面分析一下,這SQL可能是因為第二條導致的,blacklist_ip_count_date這個表的確主鍵不是IP,SELECT是多列的,那么我們試試單獨提出單表測試能不能避免臨時表: 
這里寫圖片描述
很遺憾,並不能避免,但是我們仔細看看這EXPLAIN 里面的KEY 分析,用的索引是date單字段的索引。這好像就是導致了第一條的問題了,相當於GROUP BY沒有用索引。那么我們試試強制使用IP單字段的索引呢? 
這里寫圖片描述
這里看來的確是索引的問題,導致了臨時表啊,然而再看看ROWS的數量,原來的9W變成了1552W,這不是不是撿了芝麻掉了西瓜嗎? 
這里單列索引 避免了臨時表可是聯系的行數又增加了,那么我們再試試復合索引呢? 
於是創建attack_count、date、ip的復合索引index_Acount_date_ip 
這里寫圖片描述
ROWS的行數770W而且還是有臨時表,看來這復合索引也是不可取。 
到此,避免臨時表方法失敗了,我們得從其他角度想想如何優化。 
其實,9W的臨時表並不算多,那么為什么導致會這么久的查詢呢?我們想想這沒優化的SQL的執行過程是怎么樣的呢?

網上搜索得知內聯表查詢一般的執行過程是:
1、執行FROM語句 2、執行ON過濾 3、添加外部行 4、執行where條件過濾 5、執行group by分組語句 6、執行having 7、select列表 8、執行distinct去重復數據 9、執行order by字句 10、執行limit字句
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

這里得知,Mysql 是先執行內聯表然后再進行條件查詢的最后再分組,那么想想這SQL的條件查詢和分組都只是一個表的,內聯后數據就變得臃腫了,這時候再進行條件查詢和分組是否太吃虧了,我們可以嘗試一下提前進行分組和條件查詢,實現方法就是子查詢聯合內聯查詢。 
這里寫圖片描述
這里EXPLAIN看來,只是多了子查詢,ROWS和臨時表都沒有變化。那么我們看看實際的效果呢? 
這里寫圖片描述
可見,取出來的數據完全一模一樣,可是優化后效率從原來的330秒變成了0.28秒,這里足足提升了1000多倍的速度。這也基本滿足了我們的優化需求。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM