FULLTEXT索引需要更长时间才能执行

时间:2016-11-22 07:52:01

标签: mysql count innodb sql-tuning fulltext-index

以下查询需要执行1.1s,EXPLAIN显示使用FULLTEXT索引:

SELECT SQL_NO_CACHE COUNT(*)
FROM e_entity
WHERE meta_oid=336799 AND MATCH(sIndex07) AGAINST ("#UPR-1393#" IN NATURAL LANGUAGE MODE)

EXPLAIN:
id: 1
select_type: SIMPLE
table: e_entity
type: fulltext
possible_keys: App_Parent,sindex07
key: sIndex07
key_len: 0
ref: (NULL)
rows: 1
extra: Using Where

FULLTEXT列上有sIndex07个索引。但是,如果删除此FULLTEXT索引并替换为通常的KEY索引,则查询:

SELECT SQL_NO_CACHE COUNT(*)
FROM e_entity
WHERE meta_oid=336799 AND sIndex07 LIKE "%#UPR-1393#%"

EXPLAIN:
id: 1
select_type: SIMPLE
table: e_entity
type: ref
possible_keys: App_Parent
key: App_Parent
key_len: 4
ref: const
rows: 331283
extra: Using Where

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(1022) NOT NULL,
`SINDEX11` varchar(1024) NOT NULL,
`SINDEX12` varchar(1024) NOT NULL,
`SINDEX13` varchar(1024) NOT NULL,
`SINDEX14` varchar(1024) NOT NULL,
`sIndex15` varchar(1022) 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 `E_E_OID` (`E_E_OID`),
KEY `sIndex01` (`SINDEX01`),
KEY `sIndex02` (`SINDEX02`),
KEY `sIndex03` (`SINDEX03`),
KEY `sIndex04` (`SINDEX04`),
KEY `sIndex05` (`SINDEX05`),
KEY `sIndex06` (`SINDEX06`),
FULLTEXT `sIndex07` (`SINDEX07`),
KEY `sIndex08` (`SINDEX08`),
KEY `sIndex09` (`SINDEX09`),
KEY `sIndex10` (`SINDEX10`),
KEY `sIndex11` (`SINDEX11`),
KEY `sIndex12` (`SINDEX12`),
KEY `sIndex13` (`SINDEX13`),
KEY `sIndex14` (`SINDEX14`),
KEY `sIndex15` (`SINDEX15`),
KEY `sIndex16` (`SINDEX16`),
KEY `sIndex17` (`SINDEX17`),
KEY `sIndex18` (`SINDEX18`),
KEY `sIndex19` (`SINDEX19`),
KEY `sIndex20` (`SINDEX20`),
KEY `dIndex01` (`DINDEX01`),
KEY `dIndex02` (`DINDEX02`),
KEY `dIndex03` (`DINDEX03`),
KEY `dIndex04` (`DINDEX04`),
KEY `dIndex05` (`DINDEX05`),
KEY `dIndex06` (`DINDEX06`),
KEY `dIndex07` (`DINDEX07`),
KEY `dIndex08` (`DINDEX08`),
KEY `dIndex09` (`DINDEX09`),
KEY `dIndex10` (`DINDEX10`),
KEY `nIndex01` (`NINDEX01`),
KEY `nIndex02` (`NINDEX02`),
KEY `nIndex03` (`NINDEX03`),
KEY `nIndex04` (`NINDEX04`),
KEY `nIndex05` (`NINDEX05`),
KEY `nIndex06` (`NINDEX06`),
KEY `nIndex07` (`NINDEX07`),
KEY `nIndex08` (`NINDEX08`),
KEY `nIndex09` (`NINDEX09`),
KEY `nIndex10` (`NINDEX10`),
KEY `rel_display` (`REL_DISPLAY`),
KEY `App_Parent` (`META_OID`),
) ENGINE=InnoDB AUTO_INCREMENT=1245843 DEFAULT CHARSET=utf8    ROW_FORMAT=COMPRESSED

仅需0.6秒即可完成。我在其他问题中看到MATCH子句需要嵌套但我不确定如何将其嵌套在COUNT语句中。 同样,在删除meta_oid子句时,使用FULLTEXT索引运行的查询运行速度比第二个查询快50%,所以看起来FULLTEXT正是一个好处,我在使用时遇到了困难它与查询的其余部分一起使用。meta_oid已建立索引,sIndex07也是varchar(1024),数据库的大小为4.5Gb。

修改 FULLTEXT搜索速度较慢的原因是因为搜索项中包含连字符,因此在特定情况下返回的数据集比LIKE运算符大得多。没有连字符的搜索确实使用FULLTEXT,执行速度比LIKE

好一百倍

我会在不到24小时内将奖金奖励给能够在不重新编译mysql二进制文件的情况下使用连字符进行搜索的人,从而使FULLTEXT更快,这是问题的最初目的。

2 个答案:

答案 0 :(得分:1)

MySQL使用查询计划程序来确定最佳解析查询的方式。通常,只使用一个索引来解析' WHERE'组件,这是从可能适用的可能索引列表中选择的。 EXPLAIN在possible_keys下显示可能的索引列表,所选索引由key标识。为了做出选择,MySQL会考虑许多因素,例如索引的唯一性,以尝试确定哪个索引最好缩小可能结果列表。

一旦缩小了索引中匹配的行列表。它将Use Where读取这些行并根据WHERE子句中的其余条件进行检查。

此操作中有许多边缘情况,有时MySQL可能做出糟糕的选择。 MySQL 5.1中的查询规划器发生了重大变化,在它再次变好之前需要一些版本。

如果没有检查数据,很难说明为什么MySQL会做出错误的选择。虽然在做:

SELECT SQL_NO_CACHE COUNT(*)
FROM e_entity
WHERE MATCH(sIndex07) AGAINST ("#UPR-1393#" IN NATURAL LANGUAGE MODE);

会告诉你MySQL使用全文索引从数据库中读取了多少行。在原始查询中,它必须解析所有这些行,反对' meta_oid = 336799'确定最终计数。

SELECT SQL_NO_CACHE COUNT(*)
FROM e_entity
WHERE meta_oid=336799

使用App_Parent上的META_OID索引告诉您MySQL读取的实际行数。在第二个查询中,它必须针对LIKE "%#UPR-1393#%"

解析这些行

如果后一个查询产生的数字远低于第一个,那么它可以解释为什么在App_Parent而不是全文索引时更快。

答案 1 :(得分:0)

MATCH(sIndex07)需要FULLTEXT索引才能有效运作。否则它与LIKE '%string%'一样糟糕(或更糟糕?)。

更多

如果没有FULLTEXT,这会使LIKE的运行速度更快:INDEX(meta_oid=336799, sIndex07)