什么是联合索引
联合索引(composite index)也叫组合索引或多列索引,是指在mysql中对一个表的多个列共同建立的索引。与单列索引不同,联合索引是同时对多个列的值进行排序和存储的索引结构。它将这些列的值按照指定的顺序组合在一起,形成一个复合键值存储在b+树索引结构中。
联合索引的特点
最左前缀原则
mysql联合索引严格遵循"最左前缀"(leftmost prefix)原则:
- 查询条件必须包含联合索引的第一列才能使用该索引
- 如果查询条件跳过了索引的第一列,则无法使用该联合索引
- 部分匹配原则:当查询条件包含索引的前几列时,可以使用索引的前面部分
例如,对于联合索引index(a,b,c):
where a=1 and b=2可以使用索引where b=2 and c=3不能使用该索引where a=1 and c=3可以使用索引的部分(a列)
索引列顺序的重要性
联合索引中列的顺序会极大影响索引效果:
- 选择性高的列应该放在前面(区分度高的列)
- 经常作为查询条件的列应该优先考虑
- 需要排序的列应该放在适当位置
例如,在用户表中,(last_name, first_name)索引和(first_name, last_name)索引的查询效果完全不同:
- 查找特定姓氏的用户时,前者效率更高
- 查找特定名字的用户时,后者效率更高
覆盖索引优势
当查询满足"覆盖索引"条件时,可以显著提高性能:
- 查询的所有列都包含在联合索引中
- 引擎可以直接从索引中获取数据,无需回表查询
- 减少了i/o操作,提高了查询速度
例如,对于索引index(user_id, create_time):
select user_id, create_time from orders where user_id=123;
这个查询可以直接从索引中获取所需数据,无需访问表数据文件。
联合索引的适用场景
- 多条件查询:当查询经常同时使用多个列作为条件时
- 排序操作:当查询需要对多个列进行排序时
- 避免回表:当查询只需要索引列的数据时
- 多列唯一约束:需要确保多列组合的唯一性时
创建联合索引的语法
create index index_name on table_name (column1, column2, column3);
或
alter table table_name add index index_name (column1, column2, column3);
联合索引的创建语法
create index index_name on table_name (column1, column2, column3, ...);
或者建表时指定:
create table table_name (
column1 datatype,
column2 datatype,
column3 datatype,
...
index index_name (column1, column2, column3)
);
联合索引的使用场景
多条件查询
当查询条件中同时包含多个列时,使用联合索引可以显著提高查询效率。典型的应用场景包括:
- 电商平台的产品筛选:例如,用户同时按"分类id"和"价格范围"筛选商品时,在(category_id, price)上建立联合索引可以加速查询。
- 用户管理系统:查询特定时间段内活跃的vip用户时,在(user_type, last_login_time)上建立索引。
排序和分组优化
联合索引对包含order by和group by子句的查询特别有效:
- 订单列表排序:当需要按"下单时间"降序并"按用户id"分组时,在(order_time desc, user_id)上建立索引可以避免文件排序。
- 报表统计:按月统计不同地区的销售额时,在(region, month)上的索引能加速分组操作。
覆盖索引
当查询的所有列都包含在索引中时,数据库可以直接从索引获取数据而无需回表:
- 用户基本信息查询:如果索引包含(user_id, username, avatar),查询这些字段时可以直接使用索引数据。
- 订单状态检查:在(order_id, status)上的索引可以快速返回订单状态而无需访问主表。
联合索引的最佳实践
选择性高的列放在前面
选择性高的列能更快缩小数据范围:
- 用户表索引设计:将唯一性高的(email)放在前面比(gender, email)更高效
- 日志表索引:将高基数的(request_time)放在低基数的(status_code)前面
常用查询条件优先
根据实际查询模式调整列顺序:
- 新闻网站:如果90%查询都是where category='tech' and publish_time>...,应将category放前面
- crm系统:如果经常按department + position查询,应按此顺序建立索引
考虑排序和分组
优化排序/分组操作的索引设计:
- 时间序列数据:对(time desc, device_id)建立索引以优化按时间倒序的分页查询
- 分析系统:在(country, product_type)上建索引以加速按这两个字段的分组统计
避免过多列
保持索引精简的建议:
- 一般不超过5列,例如(user_region, user_level, register_time)
- 过多列会导致:
- 索引存储空间大幅增加
- 插入/更新性能下降
- 索引合并效率降低
其他实践建议
- 定期监控索引使用情况,删除未使用的冗余索引
- 对于组合查询,考虑使用include子句(某些数据库支持)
- 注意索引列的数据类型匹配,避免隐式转换导致索引失效
联合索引示例
假设有一个用户表users:
create table users (
id int primary key,
last_name varchar(50),
first_name varchar(50),
age int,
city varchar(50),
index idx_name (last_name, first_name),
index idx_city_age (city, age)
);
查询示例:
- 能使用idx_name索引的查询:
select * from users where last_name = 'smith'; select * from users where last_name = 'smith' and first_name = 'john';
- 不能使用idx_name索引的查询:
select * from users where first_name = 'john'; -- 不满足最左前缀原则
- 使用idx_city_age索引的排序优化:
select * from users where city = 'new york' order by age;
联合索引的局限性
1. 索引使用限制
当查询条件不包含联合索引的第一列时,索引通常不会被使用。这是因为联合索引遵循"最左前缀原则",索引的b+树结构是按照索引列的顺序构建的。例如:
- 对于联合索引(a,b,c)
- 查询条件包含a或a,b时可以使用索引
- 但查询条件只有b或c时,索引将失效
- 例外情况:当查询只包含索引中的某些列但使用覆盖索引时,仍可能使用索引
2. 存储空间占用
联合索引会占用更多的存储空间,因为:
- 每个索引条目需要存储多个列的值
- 随着索引列的增加,索引的大小会成比例增长
- 对于大型表,联合索引可能占用可观的磁盘空间 示例:一个包含3个int列的联合索引比单列索引多占用2倍的存储空间
3. 更新性能影响
对联合索引的更新操作(insert、update、delete)会比单列索引更耗时,因为:
- 每次数据修改需要维护更多的索引结构
- 索引列的更新可能导致索引树的重组
- 在高并发写入场景下,可能成为性能瓶颈 应用场景:在oltp系统中,过多的联合索引可能降低写入性能
优化建议
通过合理设计和使用联合索引,可以显著提高mysql数据库的查询性能,特别是在处理多条件查询和排序操作时。建议:
- 根据实际查询模式设计索引列顺序
- 控制联合索引的列数量(通常不超过3-5列)
- 定期监控索引使用情况,删除冗余索引
- 对于频繁写入但很少查询的列,谨慎添加索引
到此这篇关于mysql联合索引的实现示例的文章就介绍到这了,更多相关mysql 联合索引内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论