【问题标题】:Fulltext search very slow with ORDER BY on other column on MySQL DB在 MySQL DB 上的其他列上使用 ORDER BY 进行全文搜索非常慢
【发布时间】:2018-01-14 19:06:41
【问题描述】:

我一直在查询 MySQL 数据库中的 InnoDB 表。 我需要基于两个文本字段的全文搜索来查找订单,其中包含 json 编码文本中的订单和客户详细信息。 这是表架构:

+--------------+------------+------+-----+---------+----------------+
| 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 VM 上处理查询大约需要 30 秒。

没有排序

ORDER BY id DESC
查询的处理速度要快得多,大约需要 0.6 秒。

EXPLAIN 结果的唯一区别是更快的查询中缺少“使用文件排序”。测量查询表明 98% 的处理时间(27 秒)用于“创建排序索引”。

有什么方法可以在合理的处理时间(不到一秒)内使用 ORDER BY 对该表进行全文搜索?

我已经尝试过不同的方法,例如将按列的顺序放入全文索引(text_id 作为 TEXT 列)没有运气。 这里的方法:How to make a FULLTEXT search with ORDER BY fast? 也没有更快。

由于应用程序在共享主机上运行,​​我在优化 MySQL ini 值或内存值方面非常有限。

非常感谢!

【问题讨论】:

  • 你有通常的选择:标准化你的数据。关系数据库最适合结构化数据(“sql”中的“s”代表“结构化”)。全文索引也因稀有词而蓬勃发展。 Json-data 是非结构化数据。因此,虽然易于存储,但很难评估(尝试列出您上个月销售的所有产品)。如果你是例如查找“mr. white”,只查找您知道包含(sur)名称的列比查找产品(“white socks”)或地址(“white house”)要快得多。因为列表更短,也可以针对order by 进行优化(没有全文索引)。
  • 如果这实际上是“只是”一个数据转储(并且您以结构化方式在其他地方拥有数据,或者不需要以任何其他方式评估它而不是在其中搜索),您可以(也许只是另外)使用不同的数据库/搜索引擎,如 elasticsearch、solr 或 sphinx(这是一个不完整的列表,没有任何特定的顺序)。他们专注于搜索大量(非结构化)数据,因此它可能是比关系数据库更好的选择。
  • 感谢您的回答。它确实只是一个数据转储,实际上是制作时完整订单的副本。我可以使用相应的表格搜索文章和客户数据,但我希望使用全文索引(大多数情况下非常快)搜索单个文本列会更容易和更快。我不知道全文和 order by 的问题。
  • 嗯,这取决于您的搜索方式。全文索引有其用途,可以成为非常有用的工具。缺点是不能和其他索引结合,所以它必须返回任何地方包含关键字的所有内容,然后排序,然后限制为 20。如果你正在寻找中间的稀有词,这非常非常有效一个列(因为 mysql 中的任何其他方法都需要全表扫描),但如果每个人都购买白袜子,效果会降低。全表扫描(按 id 排序)效率更高,因为它可以在找到 20 行后停止。
  • 好的,再次感谢。所以看来我必须找到另一个解决方案。但是很好理解mysql中全文搜索的弊端。

标签: mysql full-text-search


【解决方案1】:

使用送来的餐桌可能会节省一些时间。 试试吧。

查询

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 秒。也许在那个先决条件下这是不可能的?!
猜你喜欢
  • 2013-04-30
  • 2018-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多