【轉】導致SQL執行慢的原因
索引對大數據的查詢速度的提升是非常大的,Explain可以幫你分析SQL語句是否用到相關索引。
索引類似大學圖書館建書目索引,可以提高數據檢索的效率,降低數據庫的IO成本。MySQL在300萬條記錄左右性能開始逐漸下降,雖然官方文檔說500~800w記錄,所以大數據量建立索引是非常有必要的。MySQL提供了Explain,用於顯示SQL執行的詳細信息,可以進行索引的優化。
一、導致SQL執行慢的原因:
1. 硬件問題。如網絡速度慢,內存不足,I/O吞吐量小,磁盤空間滿了等。
2. 沒有索引或者索引失效。(一般在互聯網公司,DBA會在半夜把表鎖了,重新建立一遍索引,因為當你刪除某個數據的時候,索引的樹結構就不完整了。所以互聯網公司的數據做的是假刪除.一是為了做數據分析,二是為了不破壞索引 )
3. 數據過多(分庫分表)
4. 服務器調優及各個參數設置(調整my.cnf)
二、分析原因時,一定要找切入點:
1. 先觀察,開啟慢查詢日誌,設置相應的閾值(比如超過3秒就是慢SQL),在生產環境跑上個一天過後,看看哪些SQL比較慢。
2. Explain和慢SQL分析。比如SQL語句寫的爛,索引沒有或失效,關聯查詢太多(有時候是設計缺陷或者不得以的需求)等等。
3. Show Profile是比Explain更近一步的執行細節,可以查詢到執行每一個SQL都幹了什麽事,這些事分別花了多少秒。
4. 找DBA或者運維對MySQL進行服務器的參數調優。
三、什麽是索引?
MySQL官方對索引的定義為:索引(Index)是幫助MySQL高效獲取數據的數據結構。我們可以簡單理解為:快速查找排好序的一種數據結構。Mysql索引主要有兩種結構:B+Tree索引和Hash索引。我們平常所說的索引,如果沒有特別指明,一般都是指B樹結構組織的索引(B+Tree索引)。索引如圖所示:
最外層淺藍色磁盤塊1裏有數據17、35(深藍色)和指針P1、P2、P3(黃色)。P1指針表示小於17的磁盤塊,P2是在17-35之間,P3指向大於35的磁盤塊。真實數據存在於子葉節點也就是最底下的一層3、5、9、10、13......非葉子節點不存儲真實的數據,只存儲指引搜索方向的數據項,如17、35。
查找過程:例如搜索28數據項,首先加載磁盤塊1到內存中,發生一次I/O,用二分查找確定在P2指針。接著發現28在26和30之間,通過P2指針的地址加載磁盤塊3到內存,發生第二次I/O。用同樣的方式找到磁盤塊8,發生第三次I/O。
真實的情況是,上面3層的B+Tree可以表示上百萬的數據,上百萬的數據只發生了三次I/O而不是上百萬次I/O,時間提升是巨大的。
四、Explain分析
前文鋪墊完成,進入實操部分,先來插入測試需要的數據:
CREATE TABLE `user_info` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL DEFAULT ‘‘,
`age` INT(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `name_index` (`name`)
)ENGINE = InnoDB DEFAULT CHARSET = utf8;
INSERT INTO user_info (name, age) VALUES (‘xys‘, 20);
INSERT INTO user_info (name, age) VALUES (‘a‘, 21);
INSERT INTO user_info (name, age) VALUES (‘b‘, 23);
INSERT INTO user_info (name, age) VALUES (‘c‘, 50);
INSERT INTO user_info (name, age) VALUES (‘d‘, 15);
INSERT INTO user_info (name, age) VALUES (‘e‘, 20);
INSERT INTO user_info (name, age) VALUES (‘f‘, 21);
INSERT INTO user_info (name, age) VALUES (‘g‘, 23);
INSERT INTO user_info (name, age) VALUES (‘h‘, 50);
INSERT INTO user_info (name, age) VALUES (‘i‘, 15);
CREATE TABLE `order_info` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`user_id` BIGINT(20) DEFAULT NULL,
`product_name` VARCHAR(50) NOT NULL DEFAULT ‘‘,
`productor` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `user_product_detail_index` (`user_id`, `product_name`, `productor`)
)ENGINE =