我从远处眺望你,仿佛你消失了一样。--至那些年你以为可以用到,却消失的索引。
夜已深,点支烟来记录下今天遇到的问题。
表结构如下所示:
pay_flow | CREATE TABLE `pay_flow` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`uuid` varchar(36) NOT NULL ,
`flow_type` tinyint(4) NOT NULL ,
`amount` varchar(20) NOT NULL ,
`create_time` timestamp NOT NULL ,
`operation_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`pay_id` varchar(36) NOT NULL COMMENT '支付系统的唯一ID',
`flow_status` tinyint(4) NOT NULL ,
`user_uuid` varchar(36) DEFAULT NULL COMMENT '用户ID',
`tf_uuid` varchar(20) NOT NULL DEFAULT ' ' COMMENT '交易明细ID',
`ti_uuid` varchar(20) NOT NULL DEFAULT ' ' COMMENT '还款明细ID',
`pay_status` tinyint(4) DEFAULT NULL COMMENT '1:成功,2:失败,3:需要支付,4:进行中',
`original_tf_uuid` varchar(35) NOT NULL DEFAULT '0' COMMENT '原始的链条ID',
PRIMARY KEY (`id`),
UNIQUE KEY `index_user_payid_status` (`user_uuid`,`pay_id`,`flow_status`),
KEY `pay_id` (`pay_id`),
KEY `create_time` (`create_time`),
KEY `index_original_tf_uuid` (`original_tf_uuid`),
KEY `idx_uuid` (`uuid`)
) ENGINE=InnoDB AUTO_INCREMENT=154098216
sql如下:
SELECT * FROM `pay_flow` WHERE user_uuid='511933977553843466' ORDER BY `create_time` DESC LIMIT 50;
5.6.23版本的查询计划如下:
mysql> explain SELECT * FROM `pay_flow` WHERE user_uuid='511933977553843466' ORDER BY `create_time` DESC LIMIT 50;
+----+-------------+----------+-------+-------------------------+-------------+---------+------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+-------+-------------------------+-------------+---------+------+-------+-------------+
| 1 | SIMPLE | pay_flow | index | index_user_payid_status | create_time | 4 | NULL | 54309 | Using where |
+----+-------------+----------+-------+-------------------------+-------------+---------+------+-------+-------------+
1 row in set (0.00 sec)
抛开查询计划,闭着眼都知道,就当前的表结构而言,走user_uuid列的索引,会使得查询更快,mysql只需沿着索引列向下寻找大概不到30次就能完全找到所需要的uuid结果,然后会回表取出所有数据,根据create_time列排序,取前50,便可以得到最终想要的结果。然后根据5.6的查询计划,可能要花费2的N次方的时间才可以了。
然而,当我们舍弃limit后,5.6又会呈现出另外一种查询计划出来。
mysql> explain SELECT * FROM `pay_flow` WHERE user_uuid='511933977553843466' ORDER BY `create_time` DESC;
+----+-------------+----------+------+-------------------------+-------------------------+---------+-------+-------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+-------------------------+-------------------------+---------+-------+-------+----------------------------------------------------+
| 1 | SIMPLE | pay_flow | ref | index_user_payid_status | index_user_payid_status | 111 | const | 57072 | Using index condition; Using where; Using filesort |
+----+-------------+----------+------+-------------------------+-------------------------+---------+-------+-------+----------------------------------------------------+
1 row in set (0.00 sec)
终于正常的如我们想象的那样,不明白的是,为什么当遇到limit之后,mysql就糊涂了呢。我读书少,别骗我。
正常的查询,来看5.7的表现:
5.7貌似聪明了不少。明天再看结果吧。