1. 程式人生 > 其它 >MySQL索引失效的情況

MySQL索引失效的情況

目錄

本文MySQL索引失效的各種效情況,對每種情況寫出示例SQL並在資料庫中檢視執行計劃。

一、環境資訊

CentOS 7.4

Mysql 5.7.32

二、表、資料準備

建立一張使用者表

CREATE DATABASE IF NOT EXISTS `test` DEFAULT CHARACTER SET utf8;
USE `test`;

DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user`  (
  `id` bigint NOT NULL DEFAULT 0 COMMENT '主鍵,使用者唯一id',
  `user_name` varchar(32) NOT NULL DEFAULT '' COMMENT '使用者名稱',
  `password` varchar(64) NOT NULL DEFAULT '' COMMENT '密碼',
  `email` varchar(32) NOT NULL DEFAULT '' COMMENT '郵箱',
  `phone_number` varchar(16) NOT NULL DEFAULT '' COMMENT '電話號碼',
  `avatar` varchar(256) NOT NULL DEFAULT '' COMMENT '頭像',
  `create_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '使用者賬號建立時間',
  `update_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '上次更新記錄時間',
  `last_login_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '上次登入時間',
  `status` int(2) NOT NULL DEFAULT 0 COMMENT '使用者狀態 0-正常 1-封禁',
  PRIMARY KEY (`id`)
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin COMMENT = '使用者資訊表';

建立儲存過程,插入10萬條測試資料

DROP PROCEDURE if exists insert_t_user_test;

DELIMITER $$
CREATE PROCEDURE insert_t_user_test(IN loop_times INT)
BEGIN
    DECLARE var INT DEFAULT 0;
    WHILE var < loop_times DO
        SET var = var + 1;
    	  INSERT INTO `t_user` VALUES (var, CONCAT('rkyao-', var), '123456', '[email protected]', '15251831704', 'avatar.jpg', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 0);
    END WHILE;
		COMMIT;
END $$


CALL insert_t_user_test(100000);

三、複合索引的失效情況

建立複合索引

CREATE INDEX `idx_user` ON `t_user` (`user_name`, `email`, `phone_number`);

最左字首法則

不符合最左字首法則會使索引失效,必須從索引的最左列開始查詢,且不跳過中間列,和where指定的條件順序無關。

-- where查詢欄位順序和索引定義一致
-- 走索引 命中三個欄位 user_name, email, phone_number
explain select * from t_user where user_name = 'rkyao-1' and email = '[email protected]' and phone_number = '15251831704';

-- where查詢欄位順序和索引定義不一致
-- 走索引 命中三個欄位 user_name, email, phone_number
explain select * from t_user where phone_number = '15251831704' and email = '[email protected]' and user_name = 'rkyao-1';

-- 走索引 命中兩個欄位 user_name, email
explain select * from t_user where user_name = 'rkyao-1' and email = '[email protected]';

-- 走索引 命中一個欄位 user_name
explain select * from t_user where user_name = 'rkyao-1' and phone_number = '15251831704';

-- where查詢欄位不包含索引最左邊的列
-- 不走索引
explain select * from t_user where email = '[email protected]' and phone_number = '15251831704';

or查詢

or查詢會使索引失效。

-- 不走索引
explain select * from t_user where user_name = 'rkyao-1' or email = '[email protected]';

四、單列索引的失效情況

user_nameemail欄位上分別建立單列索引

-- 刪除聯合索引
DROP INDEX `idx_user` ON `t_user`;
-- 建立單列索引
CREATE INDEX `idx_user_name` ON `t_user` (`user_name`);
CREATE INDEX `idx_user_email` ON `t_user` (`email`);

like模糊查詢使用前萬用字元

模糊查詢時使用前萬用字元匹配會使索引失效。

-- 不走索引
explain select * from t_user where user_name like '%555%';
-- 不走索引
explain select * from t_user where user_name like '%555';
-- 走索引
explain select * from t_user where user_name like '555%';
-- 走索引
explain select * from t_user where user_name like '555';

索引列上使用函式

索引列上使用函式,或者進行運算,不走索引

-- 不走索引
explain select * from t_user where concat(user_name, '123') = '555';

字串索引沒加引號

查詢字串型別欄位時,條件值沒加引號,不走索引

-- 不走索引
explain select * from t_user where user_name = 555;

使用 != 、 <>、>、<

使用不等於,不走索引。

-- 不走索引
explain select * from t_user where user_name != '555';
-- 不走索引
explain select * from t_user where user_name <> '555';
-- 不走索引
explain select * from t_user where user_name > '555';

is null 或 is not null

is null 或 is not null,不走索引。

-- 不走索引
explain select * from t_user where user_name is null;
-- 不走索引
explain select * from t_user where user_name is not null;

in 或 not in

in走索引,使用not in不走索引。

-- 走索引
explain select * from t_user where user_name in ('rkyao-6222', 'rkyao-5678');
-- 不走索引
explain select * from t_user where user_name not in ('rkyao-6222', 'rkyao-5678');

兩個單列索引and查詢

where條件裡and查詢兩個索引列時,只會有一個索引生效,也就是建立時間早的索引生效。

-- 走索引 命中user_name欄位
explain select * from t_user where email = '[email protected]' and user_name = '555';

兩個單列索引or查詢

where條件裡or查詢兩個索引列時,兩個索引都生效。

-- 走索引 命中user_name欄位
explain select * from t_user where email = '[email protected]' or user_name = '555';