优化MySQL表索引/查询

时间:2014-04-30 21:07:19

标签: mysql sql optimization indexing innodb

我有一个大约需要19秒才能运行的查询,这是很长时间的。

这是我的慢速日志的结果:

# Query_time: 19.421110  Lock_time: 0.000171 Rows_sent: 6  Rows_examined: 48515488
use c3_xchngse;
SET timestamp=1398891560;
SELECT *
                 FROM rates
                 WHERE id IN (
                    SELECT Max(id)
                    FROM rates
                    WHERE LOWER(`currency`) = LOWER('eur')
                    GROUP BY bankId
                );

我尝试添加索引,例如:

ALTER TABLE  `c3_xchngse`.`rates` ADD INDEX  `searchIndex` (  `id` ,  `currency` ,  `bankId` )

但它似乎并没有优化查询,它们一直持续很长时间。 我也尝试为上面的查询中解决的每个列添加单独的索引,但也没有帮助。

这是我的表,今天包含大约7000行:

CREATE TABLE IF NOT EXISTS `rates` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `bankId` int(11) NOT NULL,
  `currency` varchar(3) NOT NULL,
  `buy` double NOT NULL,
  `sell` double NOT NULL,
  `addDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `since` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`),
  UNIQUE KEY `Unique` (`bankId`,`currency`,`since`),
  KEY `bankId` (`bankId`),
  KEY `currency` (`currency`),
  KEY `searchIndex` (`id`,`currency`,`bankId`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='The rates' AUTO_INCREMENT=6967 ;

如何优化查询或优化表格并获得完全相同的结果,但更快?

2 个答案:

答案 0 :(得分:2)

使用LOWER(货币)会使您的索引无效。

规范化表格中的数据:

UPDATE rates SET currency = LOWER(currency) WHERE 1;

确保传递给查询的任何参数在到达查询之前都被置为小写。

此外,您可以将货币字段设置为ENUM类型以帮助进行内部索引: https://dev.mysql.com/doc/refman/5.0/en/enum.html

答案 1 :(得分:1)

这是使用join重写查询(有时可能是有益的):

select r.*
from rates r join
     (select max(id)
      from rates
      where `currency` = 'Eur'
      group by bankId
     ) rmax
     on r.id = rmax.id;

请注意诺亚建议删除lower()。如果您具有区分大小写的排序规则,请确保大小写正确。不要在currency附近放置一个函数;这排除了使用索引。您想要的索引是rates(currency, bankId, id)

您正在尝试为id的每个银行查找最大eur的所有费率信息。您也可以使用not exists

表达此信息
select r.*
from rates r
where not exists (select 1
                  from rates r2
                  where r2.bankid = r.bankid and
                        r2.currency = 'Eur' and
                        r2.id > r.id
                 );

使用rates(bankid, currency, id)上的索引,这可能会有更好的效果。