MySQL 大型 table 按发行排序

MySQL Order By Issue on large table

我有以下 mysql 命令:

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

这是table:

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 上存在瓶颈。 table中有471000行,我假设执行order by的匹配结果集是171000行。我可以遵循哪些建议来提高性能?

您需要为 clause.Please 遵循 link

的顺序创建非聚簇索引

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

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

中所述

In some cases, MySQL cannot use indexes to resolve the ORDER BY, although it still uses indexes to find the rows that match the WHERE clause. These cases include the following:

  • There is an index on only a prefix of a column named in the ORDER BY clause. In this case, the index cannot be used to fully resolve the sort order. For example, if only the first 10 bytes of a CHAR(20) column are indexed, the index cannot distinguish values past the 10th byte and a filesort will be needed.

文件排序需要在应用 limit 之前从 table 中读取所有 171k 行。因此,为了加快查询速度,您必须让索引中的整个列都支持 order by,如果不对 table.

稍作修改,这是不可能的

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

然后将 SINDEXxx-列的 charmap 更改为每个字符使用 1 个字节的任何内容(例如 latin1),因为 utf8 将使用(最多)3 个字节,因此勉强超过密钥大小限制,或者,如果那是不可能的,因为你实际上需要 utf8-characters in that column,稍微减少你的列长度,例如1022.

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