MySQL FullText搜索限制返回空结果

时间:2016-12-27 02:13:46

标签: mysql

我有一个这样的表(我删除了所有那些不相关的字段):

CREATE TABLE `products` (
  `id` bigint(20) NOT NULL,
  `keywords` varchar(2000) DEFAULT NULL,
  PRIMARY KEY (`id`),
  FULLTEXT KEY `KEYWORDS_FTIDX` (`keywords`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

有两行:

  1. id:131072,关键字:product1
  2. id:131073,keywords:product2
  3. 如果我运行查询SELECT * FROM products WHERE MATCH(keywords) AGAINST('product1' IN BOOLEAN MODE),它将返回我预期的第一行。

    但是,如果我将限制添加到查询SELECT * FROM products WHERE MATCH(keywords) AGAINST('product1' IN BOOLEAN MODE) LIMIT 10,那么我什么都没有。

    我尝试为LIMIT SELECT * FROM products WHERE MATCH(keywords) AGAINST('product1' IN BOOLEAN MODE) LIMIT 100使用更大的数字,它再次有效。

    有谁能告诉我如何做到这一点?

1 个答案:

答案 0 :(得分:0)

我很久以前就读过有关全文索引实现的内容。关于某些索引引擎只是将任何已删除的记录标记为已删除而不是从索引中删除它们,并且这些已删除的项目可以被索引搜索操作命中,并在返回给用户之前从最终结果中删除

因此,如果mysql以这种方式工作,那么我使用LIMIT和MATCH,mysql可能只搜索索引的最开头以获得更好的性能。但是所有这些行都已被删除,这就是我得到空结果的原因。

然后我做了那些,结果证明了它:

  1. 创建测试表使用我在问题部分中发布的完全相同的查询。
  2. 插入两行:id:1,关键字:product1,id:2,keywords:product2。
  3. 运行搜索查询:SELECT * FROM products WHERE MATCH(keywords) AGAINST('product1' IN BOOLEAN MODE) LIMIT 1,然后我得到了正确的结果。
  4. 删除所有这两条记录并重新插入。
  5. 从步骤3运行查询,然后我什么都没有。
  6. 但如果我跑:SELECT * FROM products WHERE MATCH(keywords) AGAINST('product1' IN BOOLEAN MODE) LIMIT 2,它会再次返回正确的结果。
  7. 所以现在,快速修复可以将匹配条件与另一个匹配。在这种情况下,mysql将获取比匹配阶段所需更多的内容。此查询有效:SELECT * FROM products WHERE MATCH(keywords) AGAINST('product1' IN BOOLEAN MODE) AND id >= 0 LIMIT 1

    我还对查询进行了解释,它也使用了KEYWORDS_FTIDX索引。

    来自MySQL Doc(https://dev.mysql.com/doc/refman/5.6/en/innodb-fulltext-index.html)的那些行也可能与此问题有关:

    删除具有全文索引列的记录可能会导致辅助索引表中出现大量小删除,从而使这些表的并发访问成为争用的焦点。为避免此问题,每当从索引表中删除记录时,已删除文档的文档ID(DOC_ID)将记录在特殊的FTS_ _DELETED表中,并且索引记录将保留在全文索引中。在返回查询结果之前,FTS _ _DELETED表中的信息用于过滤掉已删除的文档ID。这种设计的好处是删除快速且廉价。缺点是删除记录后索引的大小不会立即减少。要删除已删除记录的全文索引条目,必须使用innodb_optimize_fulltext_only = ON在索引表上运行OPTIMIZE TABLE以重建全文索引。有关更多信息,请参阅优化InnoDB全文索引。