MySQL如何创建正确的索引

时间:2015-08-31 18:08:22

标签: mysql indexing b-tree explain sql-execution-plan

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...

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

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

2 个答案:

答案 0 :(得分:0)

索引表的基础是使查询轻松以提高性能,要添加的第一个索引应始终是表的主键(在本例中为trans_id),之后,其他id列应该也被编入索引。

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

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

答案 1 :(得分:0)

计划A

WHERE的任何col = constant子句开始。然后继续前进一个

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

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

计划B

trans_id列表中你真的只有SELECT吗?如果是这样,那么把它变成"覆盖"指数。这是一个索引,其中整个操作可以在索引所在的BTree中执行,从而避免不得不覆盖数据。

要构建此类,首先构建最佳非覆盖索引,然后在查询中添加 where 中提到的其余字段。这些都应该有效:

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查询。