MySQL在大表上按顺序排序

时间:2016-10-18 09:49:30

标签: mysql select sql-order-by innodb

我有以下mysql命令:

SELECT e.sIndex01 
FROM e_entity e 
WHERE e.meta_oid=336799 
ORDER BY e.sIndex02
LIMIT 100 OFFSET 0

这是表格:

CREATE TABLE `e_entity` (
  `OID` int(11) NOT NULL AUTO_INCREMENT,
  `E_E_OID` int(11) DEFAULT NULL,
  `UNIQUE_IDX` int(11) NOT NULL,
  `APP_OID` int(11) NOT NULL,
  `META_OID` int(11) NOT NULL,
  `STORE_DATE` datetime NOT NULL,
  `REL_DISPLAY` varchar(1024) NOT NULL,
  `SINDEX01` varchar(1024) NOT NULL,
  `SINDEX02` varchar(1024) NOT NULL,
  `SINDEX03` varchar(1024) NOT NULL,
  `SINDEX04` varchar(1024) NOT NULL,
  `SINDEX05` varchar(1024) NOT NULL,
  `SINDEX06` varchar(1024) NOT NULL,
  `SINDEX07` varchar(1024) NOT NULL,
  `SINDEX08` varchar(1024) NOT NULL,
  `SINDEX09` varchar(1024) NOT NULL,
  `SINDEX10` varchar(1024) NOT NULL,
  `SINDEX11` varchar(1024) NOT NULL,
  `SINDEX12` varchar(1024) NOT NULL,
  `SINDEX13` varchar(1024) NOT NULL,
  `SINDEX14` varchar(1024) NOT NULL,
  `SINDEX15` varchar(1024) NOT NULL,
  `SINDEX16` varchar(1024) NOT NULL,
  `SINDEX17` varchar(1024) NOT NULL,
  `SINDEX18` varchar(1024) NOT NULL,
  `SINDEX19` varchar(1024) NOT NULL,
  `SINDEX20` varchar(1024) NOT NULL,
  `NINDEX01` double NOT NULL,
  `NINDEX02` double NOT NULL,
  `NINDEX03` double NOT NULL,
  `NINDEX04` double NOT NULL,
  `NINDEX05` double NOT NULL,
  `NINDEX06` double NOT NULL,
  `NINDEX07` double NOT NULL,
  `NINDEX08` double NOT NULL,
  `NINDEX09` double NOT NULL,
  `NINDEX10` double NOT NULL,
  `DINDEX01` datetime NOT NULL,
  `DINDEX02` datetime NOT NULL,
  `DINDEX03` datetime NOT NULL,
  `DINDEX04` datetime NOT NULL,
  `DINDEX05` datetime NOT NULL,
  `DINDEX06` datetime NOT NULL,
  `DINDEX07` datetime NOT NULL,
  `DINDEX08` datetime NOT NULL,
  `DINDEX09` datetime NOT NULL,
  `DINDEX10` datetime NOT NULL,
  `FREETEXT` mediumtext NOT NULL,
  `UID` int(11) DEFAULT NULL,
  PRIMARY KEY (`OID`),
  KEY `App_Parent` (`META_OID`),
  KEY `sindex01` (`META_OID`,`SINDEX01`(64)),
  KEY `sindex02` (`META_OID`,`SINDEX02`(64)),
  KEY `sindex03` (`META_OID`,`SINDEX03`(64)),
  KEY `sindex04` (`META_OID`,`SINDEX04`(64)),
  KEY `sindex05` (`META_OID`,`SINDEX05`(64)),
  KEY `sindex06` (`META_OID`,`SINDEX06`(64)),
  KEY `sindex07` (`META_OID`,`SINDEX07`(64)),
  KEY `sindex08` (`META_OID`,`SINDEX08`(64)),
  KEY `sindex09` (`META_OID`,`SINDEX09`(64)),
  KEY `sindex10` (`META_OID`,`SINDEX10`(64)),
  KEY `nindex01` (`META_OID`,`NINDEX01`),
  KEY `nindex02` (`META_OID`,`NINDEX02`),
  KEY `nindex03` (`META_OID`,`NINDEX03`),
  KEY `nindex04` (`META_OID`,`NINDEX04`),
  KEY `nindex05` (`META_OID`,`NINDEX05`),
  KEY `dindex01` (`META_OID`,`DINDEX01`),
  KEY `dindex02` (`META_OID`,`DINDEX02`),
  KEY `dindex03` (`META_OID`,`DINDEX03`),
  KEY `dindex04` (`META_OID`,`DINDEX04`),
  KEY `dindex05` (`META_OID`,`DINDEX05`),
  KEY `sindex11` (`META_OID`,`SINDEX11`(64)),
  KEY `sindex12` (`META_OID`,`SINDEX12`(64)),
  KEY `sindex13` (`META_OID`,`SINDEX13`(64)),
  KEY `sindex14` (`META_OID`,`SINDEX14`(64)),
  KEY `sindex15` (`META_OID`,`SINDEX15`(64)),
  KEY `sindex16` (`META_OID`,`SINDEX16`(64)),
  KEY `sindex17` (`META_OID`,`SINDEX17`(64)),
  KEY `sindex18` (`META_OID`,`SINDEX18`(64)),
  KEY `sindex19` (`META_OID`,`SINDEX19`(64)),
  KEY `sindex20` (`META_OID`,`SINDEX20`(64)),
  KEY `nindex06` (`META_OID`,`NINDEX06`),
  KEY `nindex07` (`META_OID`,`NINDEX07`),
  KEY `nindex08` (`META_OID`,`NINDEX08`),
  KEY `nindex09` (`META_OID`,`NINDEX09`),
  KEY `nindex10` (`META_OID`,`NINDEX10`),
  KEY `dindex06` (`META_OID`,`DINDEX06`),
  KEY `dindex07` (`META_OID`,`DINDEX07`),
  KEY `dindex08` (`META_OID`,`DINDEX08`),
  KEY `dindex09` (`META_OID`,`DINDEX09`),
  KEY `dindex10` (`META_OID`,`DINDEX10`),
  KEY `E_E_OID` (`E_E_OID`)
) ENGINE=InnoDB AUTO_INCREMENT=469158 DEFAULT CHARSET=utf8;

上述查询需要几分钟才能完成,但是如果没有order by子句则只需要5秒钟,因此order by显然存在瓶颈。表中有471000行,我假设执行order by的匹配结果集是171000行。我可以遵循哪些建议来提高绩效?

2 个答案:

答案 0 :(得分:1)

MySQL不能使用前缀索引sIndex02order by,如documentation

中所述
  

在某些情况下,MySQL无法使用索引来解析ORDER BY,尽管它仍然使用索引来查找与WHERE子句匹配的行。这些案例包括以下内容:

     
      
  • 只有ORDER BY子句中指定的列的前缀有索引。在这种情况下,索引不能用于完全解析排序顺序。例如,如果仅对CHAR(20)列的前10个字节编制索引,则索引无法区分超过第10个字节的值,并且将需要filesort。
  •   

在应用limit之前,filesort将需要从表中读取所有171k行。因此,为了加快查询速度,您必须在索引中使用整列来支持order by,如果不对您的表稍作修改,这是不可能的。

首先,启用配置选项innodb_large_prefix(如果使用MySQL< 5.7.7,否则默认启用)将密钥大小限制增加到3072字节。

然后将SINDEXxx - 列的charmap更改为每个字符使用1个字节的任何字符(例如latin1),因为utf8将使用(最多)3个字节,因此几乎没有超出密钥大小限制,或者,如果由于您实际需要utf8 - 该列中的字符而无法实现,则将列长度略微缩小为例如1022。

如果所有这些都不可能(因为您需要utf8且长度为1024),您可以为每个sindexxx添加一个长度为1022的附加列,添加一个触发器(或存储前1022个字符的生成列,使用META_OID添加索引,新列和order by一个 - 假设您可以使用最后2个字符排序。但是因为你只有171k行,所以前1022个字符应该足够重要。

答案 1 :(得分:0)

您需要为order by和where子句创建非群集索引。请按照链接

https://dev.mysql.com/doc/refman/5.7/en/innodb-index-types.html