MySQL如何创建正确的索引

Posted

技术标签:

【中文标题】MySQL如何创建正确的索引【英文标题】:MySQL how to create a correct index 【发布时间】:2015-08-31 18:08:21 【问题描述】:

mysql 5.5

我正在尝试为查询找到正确的索引。

表:

create table trans (
  trans_id int(11) not null auto_increment,
  acct_id int(11) not null,
  status_id int(11) not null,
  trans_transaction_type varchar(5) not null,
  trans_amount float(9,3) default null,
  trans_datetime datetime not null default '0000-00-00 00:00:00',
  primary key (trans_id)
)

查询:

select trans_id
from trans 
where acct_id = _acctid
and transaction_type in ('_1','_2','_3','_4') 
and trans_datetime between _start and _end 
and status_id = 6

基数:

select * 
from information_schema.statistics 
where table_name='trans'

结果:

trans_id                    424339375
acct_id                     12123818
trans_transaction_type      70722272
trans_datetime              84866726
status_id                         22

我正在尝试查找查询的正确索引是什么?

alter table trans add index (acct_id, trans_transaction_type, trans_datetime, status_id);
alter table trans add index (acct_id, trans_datetime, trans_transaction_type, status_id);   
etc...

哪些列在索引中排在第一位?

目标是查询速度/性能。磁盘空间使用无关紧要。

【问题讨论】:

【参考方案1】:

索引一个表的基础是让查询更轻以提高性能,要添加的第一个索引应该始终是表的主键(在这种情况下为trans_id),然后其他id列应该也被索引。

alter table trans add index (trans_id, acct_id, status_id);

其他字段不需要作为索引,除非您根据它们过于频繁地查询。

【讨论】:

首先放置trans_id 会使索引不可用。并且它与PRIMARY KEY(trans_id) 是冗余的,这(在 InnoDB 中)意味着数据是一个大的 BTree,首先用 trans_id 组织。【参考方案2】:

A计划

从任何WHERE 子句开始,即col = constant。然后继续一件事

建议你添加以下两个,因为不容易预测哪个会更好:

INDEX(acct_id, status_id, transaction_type)
INDEX(acct_id, status_id, trans_datetime)

B计划

SELECT 列表中真的只有 trans_id 吗?如果是这样,那么将其变成“覆盖”索引应该不错。这是一个索引,其中整个操作都可以在索引所在的 BTree 中执行,从而避免进入数据。

要构建这样的,首先构建最佳的非覆盖索引,然后在查询中添加 anywhere 中提到的其余字段。这些中的任何一个都应该工作:

INDEX(acct_id, status_id, trans_datetime, transaction_type, trans_id)
INDEX(acct_id, status_id, transaction_type, trans_datetime, trans_id)

前两个字段可以按任意顺序排列(均为“=”)。最后两个字段可以按任意顺序排列(对于查找行都无用;它们仅用于“覆盖”)。

我建议不要在索引中包含超过 5 列。

More info in my Index Cookbook.

备注

执行EXPLAIN SELECT。当它是“覆盖”索引时,您应该会看到“使用索引”。

我认为 EXPLAIN's Key_len 将(在此处的所有情况下)仅显示 acct_idstatus_id 的组合长度。

您在存储过程中?如果 SP 中的版本运行速度明显慢于您进行试验时,您可能需要将查询重新编码为 CONCATPREPAREEXECUTE

【讨论】:

以上是关于MySQL如何创建正确的索引的主要内容,如果未能解决你的问题,请参考以下文章

#yyds干货盘点# MySQL性能优化:如何高效正确的使用索引

如何正确索引 MySQL 中多对多连接的链接表?

Mysql-如何正确的使用索引以及索引的原理

如何理解并正确使用 MySQL 索引

一个案例彻底弄懂如何正确使用 mysql inndb 联合索引

一个案例彻底弄懂如何正确使用 mysql inndb 联合索引