SQL思考題-實踐-解題

假設有一張訂單表 order,主要包含了主鍵訂單編碼 order_no、訂單狀態 status、提交時間 create_time 等列,並且創建了 status 列索引和 create_time 列索引。此時通過創建時間降序獲取狀態爲 1 的訂單編碼,以下是具體實現代碼:

select order_no from order where status =1 order by create_time desc

你知道其中的問題所在嗎?我們又該如何優化?

實踐

1. 造數據

創建表order01,主鍵索引,status,create_time 索引

CREATE TABLE `order01`  (
  `oder_no` bigint(0) NOT NULL AUTO_INCREMENT,
  `status` bigint(0) NULL DEFAULT NULL,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `create_time` datetime(0) NULL DEFAULT NULL,
  PRIMARY KEY (`oder_no`) USING BTREE,
  INDEX `idx_status`(`status`) USING BTREE,
  INDEX `idx_create_time`(`create_time`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

創建表order02,主鍵索引,status和create_time 聯合索引

CREATE TABLE `order02`  (
  `id` bigint(0) NOT NULL AUTO_INCREMENT,
  `status` bigint(0) NULL DEFAULT NULL,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `create_time` datetime(0) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `idx_status_create_time`(`status`, `create_time`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

隨機插入10000條數據,方便測試

DROP PROCEDURE IF EXISTS proc_initData;--如果存在此存儲過程則刪掉
DELIMITER $
CREATE PROCEDURE proc_initData()
BEGIN
    DECLARE i INT DEFAULT 1;
    WHILE i<=10000 DO
        insert into order01(STATUS,name,create_time) VALUES(RAND()*10000000,RAND()*10000000,now());
        SET i = i+1;
    END WHILE;
END $
CALL proc_initData();

執行完,我手動把1000條數據的status值置爲1,方便測試。

2. 查看執行計劃

EXPLAIN select * from `order01` WHERE STATUS = 1 ORDER BY create_time;
EXPLAIN select * from `order02` WHERE STATUS = 1 ORDER BY create_time;

執行時間對比


3. 結論

status和create_time單獨建索引,在查詢時只會遍歷status索引對數據進行過濾,不會用到create_time列索引,將符合條件的數據返回到server層,在server層對數據通過快排算法進行排序,Extra列會出現filesort;
應該利用索引的有序性,在status和creat_time列建立聯合索引,這樣根據status過濾後的數據就是按照create_time排好序的,避免在server層排序。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章