MySQL数据库上的其他列上的ORDER BY的全文搜索速度非常慢
我一直在处理MySQL数据库中InnoDB表的查询。 我需要基于两个文本字段的全文搜索来查找订单,其中包含json编码文本中的订单和客户详细信息。 以下是表架构:MySQL数据库上的其他列上的ORDER BY的全文搜索速度非常慢,mysql,full-text-search,Mysql,Full Text Search,我一直在处理MySQL数据库中InnoDB表的查询。 我需要基于两个文本字段的全文搜索来查找订单,其中包含json编码文本中的订单和客户详细信息。 以下是表架构: +--------------+------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+------------
+--------------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | NO | MUL | NULL | |
| comment | text | NO | | NULL | |
| modified | datetime | NO | | NULL | |
| created | datetime | NO | MUL | NULL | |
| items | mediumtext | NO | MUL | NULL | |
| addressinfo | text | NO | | NULL | |
+--------------+------------+------+-----+---------+----------------+
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| orders | 0 | PRIMARY | 1 | id | A | 69144 | NULL | NULL | | BTREE | | |
| orders | 1 | user_id | 1 | user_id | A | 45060 | NULL | NULL | | BTREE | | |
| orders | 1 | created | 1 | created | A | 69240 | NULL | NULL | | BTREE | | |
| orders | 1 | search | 1 | items | NULL | 69240 | NULL | NULL | | FULLTEXT | | |
| orders | 1 | search | 2 | addressinfo | NULL | 69240 | NULL | NULL | | FULLTEXT | | |
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
该表大约有150.000行。
它在items和addressinfo列上有一个全文索引
问题来了:
SELECT
id
FROM
orders
WHERE
MATCH (items, addressinfo) AGAINST (
'+simon* +white* ' IN BOOLEAN MODE
)
ORDER BY
id DESC
LIMIT
20
这是解释结果:
+----+-------------+--------+------------+----------+---------------+--------+---------+-------+------+----------+---------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+----------+---------------+--------+---------+-------+------+----------+---------------------------------------------------+
| 1 | SIMPLE | orders | NULL | fulltext | search | search | 0 | const | 1 | 100.00 | Using where; Ft_hints: no_ranking; Using filesort |
+----+-------------+--------+------------+----------+---------------+--------+---------+-------+------+----------+---------------------------------------------------+
在大型结果集上,在标准LAMP虚拟机上处理查询大约需要30秒
如果不按id DESC排序,查询的处理速度将在0.6秒左右加快
ORDER BY id DESC
解释结果中唯一的区别是在更快的查询中缺少“使用文件排序”。测量查询时,98%的处理时间(27秒)用于“创建排序索引”
是否有任何方法可以在合理的处理时间(少于一秒钟)内使用ORDER BY在此表上进行全文搜索
我已经尝试过不同的方法,例如将order by列放入全文索引(text_id作为text列),但没有成功。
从这里开始的方法:也不是更快
由于应用程序在共享主机上运行,我在优化MySQL ini值或内存值方面非常有限
非常感谢 使用传递的表可能会获得一些时间。 试试看 查询
SELECT
orders.id
FROM (
SELECT
id
FROM
orders
WHERE
MATCH (items, addressinfo) AGAINST (
'+simon* +white* ' IN BOOLEAN MODE
)
)
AS
orders_match
INNER JOIN
orders
ON
orders_match.id = orders.id
ORDER BY
orders.id DESC
LIMIT 20
谢谢这确实节省了大约6秒,但不幸的是,这仍然是22秒:/我需要在2秒或3秒以下。也许在那个前提下是不可能的?!您有一个常见的选择:规范化数据。关系数据库最适合于结构化数据(“sql”中的“s”代表“结构化”)。此外,全文索引也在稀有词上蓬勃发展。Json数据是非结构化数据。所以,虽然很容易储存,但评估起来却很困难(试着列出你上个月销售的所有产品)。例如,如果您正在寻找“怀特先生”,只需查找您知道包含(sur)姓名的栏目,比查找产品(“白袜子”)或地址(“白宫”)要快得多。由于列表较短,也可以按的顺序进行优化(无全文索引)。如果这实际上“只是”一个数据转储(并且您以结构化的方式在其他地方拥有数据,或者不需要以搜索以外的任何方式对其进行评估),您可以(可能只是额外)使用不同的数据库/搜索引擎,如elasticsearch、solr或sphinx(这是一个没有任何特定顺序的不完整列表)。他们专门搜索大量(非结构化)数据,因此这可能是比关系数据库更好的选择。谢谢你的回答。它实际上只是一个数据转储,实际上是制作时完整订单的副本。我可以使用相应的表搜索文章和客户数据,但我希望使用全文索引搜索单个文本列(大多数情况下非常快)会更容易、更快。我没有意识到全文和排序方式的问题。嗯,这取决于你是如何搜索的。全文索引有它的用途,可以是一个非常有用的工具。缺点是您无法将其与其他索引组合,因此它必须在任何位置返回包含关键字的所有内容,然后对其进行排序,然后将其限制为20。这是非常非常有效的,如果你在一个专栏中寻找稀有的单词(因为MySQL中的任何其他方法都需要一个完整的表格扫描),但是如果每个人都买白袜子的话,效果就会变差。一个完整的表扫描(按id排序)要高效得多,因为它可以在找到20行后立即停止。好的,再次感谢。看来我得另找解决办法了。但是很好地理解了mysql中全文搜索的缺点。