问题发现
我认为一条很简单的SQL然后跑了很久,明明我已经都建立相应的索引,逻辑也不需要优化。
SELECT a.custid, b.score, b.xcreditscore, b.lrscore FROM ( SELECT DISTINCT custid FROM sync.`credit_apply` WHERE SUBSTR(createtime, 1, 10) >= '2019-12-15' AND rejectrule = 'xxxx' ) a LEFT JOIN ( SELECT * FROM sync.`credit_creditchannel` ) b ON a.custid = b.custid;
查看索引状态:
credit_apply表
mysql> show index from sync.`credit_apply`; +--------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +--------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | credit_apply | 0 | PRIMARY | 1 | applyId | A | 1468496 | NULL | NULL | | BTREE | | | | credit_apply | 1 | index2 | 1 | custId | A | 666338 | NULL | NULL | | BTREE | | | | credit_apply | 1 | index2 | 2 | createTime | A | 1518231 | NULL | NULL | | BTREE | | | +--------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
或者
CREATE TABLE `credit_apply` ( `applyId` bigint(20) NOT NULL AUTO_INCREMENT, `custId` varchar(128) COLLATE utf8mb4_unicode_ci NOT NULL, `ruleVersion` int(11) NOT NULL DEFAULT '1', `rejectRule` varchar(128) COLLATE utf8mb4_unicode_ci DEFAULT 'DP0000', `status` tinyint(4) NOT NULL DEFAULT '0', `extra` text COLLATE utf8mb4_unicode_ci, `createTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `updateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `mobile` varchar(128) COLLATE utf8mb4_unicode_ci DEFAULT '', PRIMARY KEY (`applyId`) USING BTREE, KEY `index2` (`custId`,`createTime`) ) ENGINE=InnoDB AUTO_INCREMENT=1567035 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
sync.`credit_creditchannel`表
mysql> show index from sync.`credit_creditchannel` ; +----------------------+------------+-----------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +----------------------+------------+-----------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | credit_creditchannel | 0 | PRIMARY | 1 | recId | A | 450671 | NULL | NULL | | BTREE | | | | credit_creditchannel | 1 | nationalId_custid | 1 | nationalId | A | 450770 | NULL | NULL | | BTREE | | | | credit_creditchannel | 1 | nationalId_custid | 2 | custId | A | 450770 | NULL | NULL | YES | BTREE | | | | credit_creditchannel | 1 | credit_creditchannel_custId | 1 | custId | A | 450770 | 10 | NULL | YES | BTREE | | | +----------------------+------------+-----------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
或者
CREATE TABLE `credit_creditchannel` ( `recId` bigint(20) NOT NULL AUTO_INCREMENT, `nationalId` varchar(128) NOT NULL DEFAULT '', `identityType` varchar(3) NOT NULL DEFAULT '', `brief` mediumtext, `score` decimal(10,4) NOT NULL DEFAULT '0.0000', `npaCode` varchar(128) NOT NULL DEFAULT '', `basic` mediumtext, `createTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `updateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `request` mediumtext, `custId` varchar(128) DEFAULT '', `xcreditScore` decimal(10,4) DEFAULT '0.0000', `queryTime` varchar(24) DEFAULT '', `lrScore` decimal(10,4) DEFAULT '0.0000', PRIMARY KEY (`recId`) USING BTREE, KEY `nationalId_custid` (`nationalId`,`custId`), KEY `credit_creditchannel_custId` (`custId`(10)) ) ENGINE=InnoDB AUTO_INCREMENT=586557 DEFAULT CHARSET=utf8
我们都可以看到相应的索引。以现在简单的sql逻辑理论上走custid这个索引就好了
解释函数explain
mysql> explain SELECT a.custid, b.score, b.xcreditscore, b.lrscore FROM( SELECT DISTINCT custid FROM sync.`credit_apply` WHERE SUBSTR(createtime, 1, 10) >= '2019-12-15' AND rejectrule = 'xxx') a LEFT JOIN (select * from sync.`credit_creditchannel`) b ON a.custid = b.custid; +----+-------------+----------------------+------------+-------+---------------+--------+---------+------+---------+----------+----------------------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+----------------------+------------+-------+---------------+--------+---------+------+---------+----------+----------------------------------------------------+ | 1 | PRIMARY | <derived2> | NULL | ALL | NULL | NULL | NULL | NULL | 158107 | 100.00 | NULL | | 1 | PRIMARY | credit_creditchannel | NULL | ALL | NULL | NULL | NULL | NULL | 450770 | 100.00 | Using where; Using join buffer (Block Nested Loop) | | 2 | DERIVED | credit_apply | NULL | index | index2 | index2 | 518 | NULL | 1581075 | 10.00 | Using where | +----+-------------+----------------------+------------+-------+---------------+--------+---------+------+---------+----------+----------------------------------------------------+ 3 rows in set (0.06 sec)
如何去看我们的SQL是否走索引?
我们只需要注意一个最重要的type 的信息很明显的提现是否用到索引:
type结果
type结果值从好到坏依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
一般来说,得保证查询至少达到range级别,最好能达到ref,否则就可能会出现性能问题。
possible_keys:sql所用到的索引
key:显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL
rows: 显示MySQL认为它执行查询时必须检查的行数。
分析:
我们的credit_creditchannel是ALL,而possible_keys是NULL索引在查询该表的时候并没有用到索引怪不得这么慢!!!!!!!!!