mysql联合索引的实现示例

 更新时间:2025年12月02日 10:14:48   作者:MadeInSQL  
联合索引也叫组合索引或多列索引,是指在MySQL中对一个表的多个列共同建立的索引,与单列索引不同,联合索引是同时对多个列的值进行排序和存储的索引结构,下面就来介绍一下如何使用

什么是联合索引

联合索引(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列)

索引列顺序的重要性

联合索引中列的顺序会极大影响索引效果:

  1. 选择性高的列应该放在前面(区分度高的列)
  2. 经常作为查询条件的列应该优先考虑
  3. 需要排序的列应该放在适当位置

例如,在用户表中,(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;

这个查询可以直接从索引中获取所需数据,无需访问表数据文件。

联合索引的适用场景

  1. 多条件查询:当查询经常同时使用多个列作为条件时
  2. 排序操作:当查询需要对多个列进行排序时
  3. 避免回表:当查询只需要索引列的数据时
  4. 多列唯一约束:需要确保多列组合的唯一性时

创建联合索引的语法

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)
);

查询示例:

  1. 能使用idx_name索引的查询:
SELECT * FROM users WHERE last_name = 'Smith';
SELECT * FROM users WHERE last_name = 'Smith' AND first_name = 'John';
  1. 不能使用idx_name索引的查询:
SELECT * FROM users WHERE first_name = 'John';  -- 不满足最左前缀原则
  1. 使用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数据库的查询性能,特别是在处理多条件查询和排序操作时。建议:

  1. 根据实际查询模式设计索引列顺序
  2. 控制联合索引的列数量(通常不超过3-5列)
  3. 定期监控索引使用情况,删除冗余索引
  4. 对于频繁写入但很少查询的列,谨慎添加索引

到此这篇关于mysql联合索引的实现示例的文章就介绍到这了,更多相关mysql 联合索引内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MySQL sql_safe_updates参数详解

    MySQL sql_safe_updates参数详解

    sql_safe_updates 是 MySQL 中的一个系统变量,用于控制 MySQL 服务器是否允许在没有使用 KEY 或 LIMIT 子句的 UPDATE 或 DELETE 语句上执行更新或删除操作,这篇文章主要介绍了MySQL sql_safe_updates参数,需要的朋友可以参考下
    2024-07-07
  • Mysql迁移Postgresql的实现示例

    Mysql迁移Postgresql的实现示例

    本文主要介绍了Mysql迁移Postgresql的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • MySQL5.7.33安装过程图文详解

    MySQL5.7.33安装过程图文详解

    这篇文章主要介绍了MySQL5.7.33安装过程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03
  • 登录mysql时出现的闪退问题解决

    登录mysql时出现的闪退问题解决

    大家在打开MySQL时,可能会遇到在登陆界面输入密码之后就闪退的这个问题,下面这篇文章主要给大家介绍了关于如何解决登录mysql时出现的闪退问题的相关资料,需要的朋友可以参考下
    2023-05-05
  • MYSQL数据库查询按日期分组统计详细代码

    MYSQL数据库查询按日期分组统计详细代码

    这篇文章主要给大家介绍了关于MYSQL数据库查询按日期分组统计的相关资料,按日期分组是指按照时间维度对数据进行分类汇总统计,常用于查询分析具有时间属性的数据,例如订单量、用户活跃等,需要的朋友可以参考下
    2024-01-01
  • Mysql 导入导出csv 中文乱码问题的解决方法

    Mysql 导入导出csv 中文乱码问题的解决方法

    这篇文章介绍了Mysql 导入导出csv 中文乱码问题的解决方法,有需要的朋友可以参考一下
    2013-09-09
  • 一条SQL语句在MySQL中是如何执行的

    一条SQL语句在MySQL中是如何执行的

    本篇文章会分析下一个sql语句在mysql中的执行流程,包括sql的查询在mysql内部会怎么流转,sql语句的更新是怎么完成的,需要的朋友可以参考一下
    2021-10-10
  • MySQL数据库迁移快速导出导入大量数据

    MySQL数据库迁移快速导出导入大量数据

    今天小编就为大家分享一篇关于MySQL数据库迁移快速导出导入大量数据,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • Ubuntu 18.04 安装mysql5.7

    Ubuntu 18.04 安装mysql5.7

    这篇文章主要为大家详细介绍了Ubuntu 18.04 安装mysql 5.7的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-02-02
  • MySQL运算符!=和<>及=和<=>的使用区别

    MySQL运算符!=和<>及=和<=>的使用区别

    本文主要介绍了MySQL运算符!=和<>及=和<=>的使用区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05

最新评论