赞
踩
CREATE TABLE user (
id int(11) NOT NULL AUTO_INCREMENT,
user_id varchar(32) NOT NULL,
age varchar(16) NOT NULL,
name varchar(255) NOT NULL,
PRIMARY KEY (id),
KEY idx_userid (user_id) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
user_id 字段为字串类型,B+树的普通索引,查询条件传数字,会导致索引失效
给数字加上 ’ ’ ,传字符串,会走索引
为什么未加单引号不走索引
CREATE TABLE user (
id int(11) NOT NULL AUTO_INCREMENT,
user_id varchar(32) NOT NULL,
age varchar(16) NOT NULL,
name varchar(255) NOT NULL,
PRIMARY KEY (id),
KEY idx_userid_name (user_id,name) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
MySQl 建立联合索引时,遵循最左前缀匹配的原则,即最左优先,建立一个(a,b,c)的联合索引,相当于建立(a)、(a,b)、(a,b,c)三个索引
查询条件列不是联合索引的第一个列,不满足最左匹配原则
在联合索引中,查询条件满足最左匹配原则时,索引才生效
CREATE TABLE account (
id int(11) NOT NULL AUTO_INCREMENT COMMENT '主键Id',
name varchar(255) DEFAULT NULL COMMENT '账户名',
balance int(11) DEFAULT NULL COMMENT '余额',
create_time datetime NOT NULL COMMENT '创建时间',
update_time datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (id),
KEY idx_name (name),
KEY idx_create_time (create_time) //索引
) ENGINE=InnoDB AUTO_INCREMENT=1570068 DEFAULT CHARSET=utf8 ROW_FORMAT=REDUNDANT COMMENT='账户表';
select id,name,balance from account where create_time> '2022-11-7' limit 100000,10;
select id,name,balance FROM account where id > 100000 limit 10;
select acct1.id,acct1.name,acct1.balance FROM account acct1 INNER JOIN (SELECT a.id FROM account a WHERE a.create_time > '2022-11-7' limit 100000, 10) AS acct2 on acct1.id= acct2.id;
select * from user where user_id in (select author_id from artilce where type = 1);
DROP TABLE IF EXISTS `staff`;
CREATE TABLE `staff` (
`id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
`id_card` varchar(20) NOT NULL COMMENT '身份证号码',
`name` varchar(64) NOT NULL COMMENT '姓名',
`age` int(4) NOT NULL COMMENT '年龄',
`city` varchar(64) NOT NULL COMMENT '城市',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8 COMMENT='员工表';
SET FOREIGN_KEY_CHECKS = 1;
order by 排序 ⇒ \Rightarrow ⇒ rowid排序 和 全字段排序
rowid排序执行过程:
select name,age,city from staff where city = '深圳' order by age limit 10;
全字段排序执行过程
select name,age,city from staff where city = '深圳' order by age limit 10;
sort_buffer 大小由 sort_buffer_size 参数决定
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`card` varchar(255) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE,
KEY `idx_card` (`card`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
单个name字段加索引,查询name非空,走索引
单个card字段加索引,查询card非空,走索引
如果用 or 连接,不走索引
因为数据量问题,导致 MySQL 优化器放弃走索引,平时用 explain 分析 SQL 的时候,如果 type=range,要注意一下,这个可能因为数据量问题,导致索引无效
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`userId` int(11) NOT NULL,
`age` int(11) DEFAULT NULL,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_age` (`age`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
age 加索引,使用 != 或者 < >,not in,进行表达式计算,索引失效
这个跟 MySQL 优化器有关,优化器觉得即使走索引,还要扫描很多行,觉得不划算,不如不走索引,平时用的 != 或者 < >,not in ,需要留意
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL,
`age` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
CREATE TABLE `user_job` (
`id` int(11) NOT NULL,
`userId` int(11) NOT NULL,
`job` varchar(255) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
左外连接查询,user_job 表走全表扫描
name 字段编码一致,相同 SQL,走索引
CREATE TABLE `staff` (
`id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
`id_card` varchar(20) NOT NULL COMMENT '身份证号码',
`name` varchar(64) NOT NULL COMMENT '姓名',
`age` int(4) NOT NULL COMMENT '年龄',
`city` varchar(64) NOT NULL COMMENT '城市',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8 COMMENT='员工表';
CREATE TABLE `old_account` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键Id',
`name` varchar(255) DEFAULT NULL COMMENT '账户名',
`balance` int(11) DEFAULT NULL COMMENT '余额',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1570068 DEFAULT CHARSET=utf8 ROW_FORMAT=REDUNDANT COMMENT='老的账户表';
CREATE TABLE `account` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键Id',
`name` varchar(255) DEFAULT NULL COMMENT '账户名',
`balance` int(11) DEFAULT NULL COMMENT '余额',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1570068 DEFAULT CHARSET=utf8 ROW_FORMAT=REDUNDANT COMMENT='账户表';
查看 delete 执行计划,发现不走索引
查看 select 执行计划,就会走索引
查看 select 语句如何执行
explain select * from account where name in (select name from old_account);
show WARNINGS; --可以查看优化后,最终执行的sql
select `employees`.`account`.`id` AS `id`,`employees`.`account`.`name` AS `name`,`employees`.`account`.`balance` AS `balance`,`employees`.`account`.`create_time` AS `create_time`,`employees`.`account`.`update_time` AS `update_time` from `employees`.`account` semi join (`employees`.`old_account`) where (`employees`.`old_account`.`name` = `employees`.`account`.`name`)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。