一分40多的sql优化到秒出,但是还有问题

2024年 3月 13日 77.5k 0

表结构

| xxl_job_log | CREATE TABLE `xxl_job_log` (

 `id` bigint NOT NULL AUTO_INCREMENT,

 `job_group` int NOT NULL COMMENT '执行器主键ID',

 `job_id` int NOT NULL COMMENT '任务,主键ID',

 `executor_address` varchar(255) DEFAULT NULL COMMENT '执行器地址,本次执行的地址',

 `executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler',

 `executor_param` varchar(512) DEFAULT NULL COMMENT '执行器任务参数',

 `executor_sharding_param` varchar(20) DEFAULT NULL COMMENT '执行器任务分片参数,格式如 1/2',

 `executor_fail_retry_count` int NOT NULL DEFAULT '0' COMMENT '失败重试次数',

 `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间',

 `trigger_code` int NOT NULL COMMENT '调度-结果',

 `trigger_msg` text COMMENT '调度-日志',

 `handle_time` datetime DEFAULT NULL COMMENT '执行-时间',

 `handle_code` int NOT NULL COMMENT '执行-状态',

 `handle_msg` text COMMENT '执行-日志',

 `alarm_status` tinyint NOT NULL DEFAULT '0' COMMENT '告警状态:0-默认、1-无需告警、2-告警成功、3-告警失败',

 PRIMARY KEY (`id`),

 KEY `I_trigger_time` (`trigger_time`),

 KEY `I_handle_code` (`handle_code`),

 KEY `idx_alarm_status` (`alarm_status`),

 KEY `i_job_id` (`job_id`) USING BTREE,

 KEY `idx_test` (`handle_code`,`alarm_status`,`trigger_code`,`id`) USING BTREE

) ENGINE=InnoDB AUTO_INCREMENT=88113582 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |

sql语句

SELECT id FROM `xxl_job_log` force index(idx_test ) WHERE !( (trigger_code in (0, 200) and handle_code = 0) OR (handle_code = 200) ) AND `alarm_status` = 0 ORDER BY id ASC LIMIT 1000 ;

说明:不要在意两次sql的执行结果,因为有状态列,会更改,导致执行结果相差。

默认sql的执行计划:

root@localhost 09:42:16 [sipi_xxl_db]> desc SELECT id FROM `xxl_job_log`   WHERE !( (trigger_code in (0, 200) and handle_code = 0) OR (handle_code = 200) ) AND `alarm_status` = 0 ORDER BY id ASC LIMIT 1000\G

*************************** 1. row ***************************

          id: 1

 select_type: SIMPLE

       table: xxl_job_log

  partitions: NULL

        type: index

possible_keys: I_handle_code,idx_alarm_status,idx_test

         key: PRIMARY

     key_len: 8

         ref: NULL

        rows: 174320

    filtered: 0.29

       Extra: Using where

1 row in set, 2 warnings (0.08 sec)

默认执行计划的执行时间

root@localhost 10:00:03 [sipi_xxl_db]>  SELECT id FROM `xxl_job_log`

   -> WHERE !(

   ->  (trigger_code in (0, 200) and handle_code = 0)

   ->   OR

   -> (handle_code = 200)

   ->  )

   ->  AND `alarm_status` = 0

   -> ORDER BY id ASC

   ->   LIMIT 1000  ;

+----------+

| id       |

+----------+

| 86366624 |

| 86367424 |

| 86368941 |

| 86368950 |

| 86368951 |

| 86368952 |

| 86368954 |

| 86368957 |

| 86368961 |

| 86368963 |

| 86368965 |

| 86368967 |

| 86368969 |

| 86368972 |

+----------+

14 rows in set, 1 warning (1 min 44.35 sec)

优化思路:

当时是handle_code最少,其次是alarm_status,然后是trigger_code,然后再包括一个id。但是现在看来应该是覆盖索引使查询更快了

root@localhost 10:06:08 [sipi_xxl_db]>  SELECT count(id) FROM `xxl_job_log`  WHERE !(trigger_code in (0, 200));

+-----------+

| count(id) |

+-----------+

|     18420 |

+-----------+

1 row in set, 1 warning (5.51 sec)

root@localhost 10:06:54 [sipi_xxl_db]>  SELECT count(id) FROM `xxl_job_log`  WHERE !(handle_code = 0);

+-----------+

| count(id) |

+-----------+

|   7546629 |

+-----------+

1 row in set, 1 warning (13.16 sec)

root@localhost 10:07:16 [sipi_xxl_db]> SELECT count(id) FROM `xxl_job_log` where  (handle_code = 200);

+-----------+

| count(id) |

+-----------+

|   7547483 |

+-----------+

1 row in set (7.58 sec)

root@localhost 10:08:03 [sipi_xxl_db]> SELECT count(id) FROM `xxl_job_log` where `alarm_status` = 0;

+-----------+

| count(id) |

+-----------+

|   7548087 |

+-----------+

1 row in set (4.39 sec)

优化方法

create index idx_test on xxl_job_log(handle_code,alarm_status,trigger_code,id);

优化后

root@localhost 10:02:45 [sipi_xxl_db]> SELECT id FROM `xxl_job_log` force index(idx_test )  

-> WHERE !(  

-> (trigger_code in (0, 200) and handle_code = 0)  

-> OR  

-> (handle_code = 200)  

-> )  

-> AND `alarm_status` = 0  

-> ORDER BY id ASC  

-> LIMIT 1000 ;

+----------+ | id | +----------+

| 86369946 |

| 86370069 |

| 86370221 |

| 86370238 |

| 86370276 |

| 86370322 |

| 86370802 |

| 86371162 |

| 86371210 |

+----------+

9 rows in set, 1 warning (0.01 sec)  

root@localhost 10:02:57 [sipi_xxl_db]>

优化后的执行计划:

root@localhost 09:42:12 [sipi_xxl_db]> desc SELECT id FROM `xxl_job_log` force index(idx_test ) WHERE !( (trigger_code in (0, 200) and handle_code = 0) OR (handle_code = 200) ) AND `alarm_status` = 0 ORDER BY id ASC LIMIT 1000\G

*************************** 1. row ***************************

id: 1

select_type: SIMPLE

table: xxl_job_log

partitions: NULL

type: range

possible_keys: idx_test

key: idx_test

key_len: 4

ref: NULL

rows: 35654

filtered: 98.30

Extra: Using where; Using index; Using filesort

1 row in set, 2 warnings (0.00 sec)

因为没有自动使用创建的索引,需要强制,于是改了sql发现可以自动使用了,or导致了没有自动使用索引

root@localhost 11:08:08 [sipi_xxl_db]> desc select * from (SELECT id FROM `xxl_job_log` WHERE ( (trigger_code not in (0, 200) ) and (handle_code != 200) )AND `alarm_status` = 0  union SELECT id FROM `xxl_job_log` WHERE handle_code != 0 and (handle_code != 200) AND `alarm_status` = 0 ) aa  ORDER BY aa.id ASC LIMIT 1000\G

*************************** 1. row ***************************          

id: 1  select_type: PRIMARY      

table:    

partitions: NULL        

type: ALLpossible_keys: NULL        

key: NULL      key_len: NULL        

ref: NULL        

rows: 14217    

filtered: 100.00      

Extra: Using filesort

*************************** 2. row ***************************          

id: 2  

select_type: DERIVED        

table: xxl_job_log  

partitions: NULL        

type: rangepossible_keys: I_handle_code,idx_alarm_status,idx_test          

key: idx_test      

key_len: 4          

ref: NULL        

rows: 35522    

filtered: 40.00        

Extra: Using where; Using index

*************************** 3. row ***************************          

id: 3  select_type: UNION      

table: xxl_job_log  

partitions: NULL        

type: rangepossible_keys: I_handle_code,idx_alarm_status,idx_test          

key: idx_test    

key_len: 4          

ref: NULL        

rows: 18    

filtered: 50.00        

Extra: Using where; Using index

*************************** 4. row ***************************          

id: NULL  

select_type: UNION RESULT        

table:    

partitions: NULL        

type: ALL

possible_keys: NULL          

key: NULL      

key_len: NULL        

ref: NULL        

rows: NULL    

filtered: NULL        

Extra: Using temporary4 rows in set, 1 warning (0.00 sec)
root@localhost 11:08:28 [sipi_xxl_db]>

相关文章

Oracle如何使用授予和撤销权限的语法和示例
Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
社区版oceanbase安装
Oracle 导出CSV工具-sqluldr2
ETL数据集成丨快速将MySQL数据迁移至Doris数据库

发布评论