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 不能使用前缀索引 sIndex02
到 order 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 个字符应该足够重要。
我有以下 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 不能使用前缀索引 sIndex02
到 order 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 个字符应该足够重要。