三道MySQL联合索引面试题,淘汰80%的面试者,你能答对几道
2023-11-10 14:21:07
写在前面
众所周知,MySQL联合索引遵循最左前缀匹配原则,在少数情况下也会不遵循(有兴趣,可以翻一下上篇文章)。创建联合索引的时候,建议优先把区分度高的字段放在第一列。至于怎么统计区分度,可以按照下面这个SQL执行:
select count(distinct 字段名)/count(*) from 表名;
第一题
假设有如下表结构:
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_username` (`username`),
KEY `idx_email` (`email`),
KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
现在有如下查询:
select * from user where username='zhangsan' and create_time>'2022-01-01 00:00:00';
请问这个查询是否会走联合索引?
解析
不会走联合索引。因为虽然查询条件中包含了username
和create_time
两个字段,但是create_time
字段没有放在联合索引的第一列,所以不满足最左前缀匹配原则。
正确姿势
创建联合索引idx_username_create_time
,字段顺序为(username, create_time)
,这样查询就可以走联合索引了。
第二题
假设有如下表结构:
CREATE TABLE `order` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`product_id` int(11) NOT NULL,
`order_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`order_status` int(11) DEFAULT NULL,
`order_amount` decimal(10,2) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_product_id` (`product_id`),
KEY `idx_order_time` (`order_time`),
KEY `idx_order_status` (`order_status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
现在有如下查询:
select * from `order` where user_id=1 and order_status=1 and order_time>'2022-01-01 00:00:00';
请问这个查询是否会走联合索引?
解析
会走联合索引。因为查询条件中包含了user_id
、order_status
和order_time
三个字段,并且这三个字段的顺序与联合索引idx_user_id_order_status_order_time
的字段顺序一致,满足最左前缀匹配原则。
第三题
假设有如下表结构:
CREATE TABLE `product` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`product_name` varchar(255) DEFAULT NULL,
`product_price` decimal(10,2) DEFAULT NULL,
`product_category` int(11) DEFAULT NULL,
`product_brand` int(11) DEFAULT NULL,
`product_status` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_product_name` (`product_name`),
KEY `idx_product_price` (`product_price`),
KEY `idx_product_category` (`product_category`),
KEY `idx_product_brand` (`product_brand`),
KEY `idx_product_status` (`product_status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
现在有如下查询:
select * from product where product_name like '%手机%' and product_price>1000 and product_category=1;
请问这个查询是否会走联合索引?
解析
不会走联合索引。因为查询条件中包含了product_name
、product_price
和product_category
三个字段,但是product_name
字段没有放在联合索引的第一列,所以不满足最左前缀匹配原则。
正确姿势
创建联合索引idx_product_name_product_price_product_category
,字段顺序为(product_name, product_price, product_category)
,这样查询就可以走联合索引了。
写在最后
联合索引的使用非常广泛,掌握联合索引的原理和使用技巧,可以有效地优化数据库性能。希望这三道面试题对大家有所帮助。