sql優化,原理減少回表操作
阿新 • • 發佈:2021-09-29
優化規則:
-- 優化前SQL SELECT 各種欄位 FROM `table_name` WHERE 各種條件 LIMIT 0,10;
----->
-- 優化後SQL SELECT 各種欄位 FROM `table_name` main_tale RIGHT JOIN ( SELECT 子查詢只查主鍵 FROM `table_name` WHERE 各種條件 LIMIT 0,10; ) temp_table ON temp_table.主鍵 = main_table.主鍵
優化案例
首先我們執行以下指令碼,創造測試資料;
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET latin1 NOT NULL,
`sex` char(1) CHARACTER SET latin1 DEFAULT NULL,
`age` tinyint(4) DEFAULT NULL,
`phone` varchar(16) CHARACTER SET latin1 DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_age` (`age`),
KEY `idx_sex` (`sex`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=5000002 DEFAULT CHARSET=utf8;
-- 定義語法結束符號 delimiter // -- 建立一個 名稱為 p2 的儲存過程 drop procedure if exists p2; create procedure p2() begin declare sex varchar(1) character set utf8; declare age,total int; -- 初始化 變數 set total = 0; -- loop 迴圈 xxx: loop IF mod(total,2) != 0 THEN set sex = 'M'; ELSEIF mod(total,2) =0 THEN set sex = 'F'; END IF; set age = mod(total,100); INSERT INTO `krisDB`.`users`(`id`, `name`, `sex`, `age`, `phone`) VALUES (total+1, 'tom'+total, sex, age, '10086'); if total = 5000000 then leave xxx; end if; -- 累計 set total = total + 1; end loop; SELECT total; end // delimiter; call p2();
優化前:
優化後:
我們可以看到節省了很多時間了。
優化原理
select * from users where sex = 'M' limit 300000,5; 查詢到索引葉子節點資料。根據葉子節點上的主鍵值,回表操作,也就是去聚簇索引上查詢需要的全部欄位值。
像上面這樣,需要查詢300005次索引節點,查詢300005次聚簇索引的資料,最後再將結果過濾掉前300000條,取出最後5條。MySQL耗費了大量隨機I/O在查詢聚簇索引的資料上,而有300000次隨機I/O查詢到的資料是不會出現在結果集當中的,那麼這部分時間是浪費的。這一點我們可以證實,因為information_schema.INNODB_BUFFER_PAGE表中有uk_sex,primary索引查詢的快取記錄。
執行查詢select * from users where sex = 'M' limit 300000,5之前
執行查詢select * from users where sex = 'M' limit 300000,5之後
優化查詢語句為SELECT * from users a RIGHT JOIN (SELECT id FROM users where sex = 'M' limit 300000,5) b on a.id = b.id;
執行查詢語句之前
執行查詢語句之後