返回

三道MySQL联合索引面试题,淘汰80%的面试者,你能答对几道

后端

写在前面

众所周知,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';

请问这个查询是否会走联合索引?

解析

不会走联合索引。因为虽然查询条件中包含了usernamecreate_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_idorder_statusorder_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_nameproduct_priceproduct_category三个字段,但是product_name字段没有放在联合索引的第一列,所以不满足最左前缀匹配原则。

正确姿势

创建联合索引idx_product_name_product_price_product_category,字段顺序为(product_name, product_price, product_category),这样查询就可以走联合索引了。

写在最后

联合索引的使用非常广泛,掌握联合索引的原理和使用技巧,可以有效地优化数据库性能。希望这三道面试题对大家有所帮助。