【发布时间】: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中全文搜索的弊端。