我有一张这样的桌子(我删除了所有不相关的字段):

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;

有两行:
编号:131072,关键字:product1
编号:131073,关键字:product2
如果运行querySELECT * FROM products WHERE MATCH(keywords) AGAINST('product1' IN BOOLEAN MODE),它将按预期返回第一行。
但是如果我给查询添加了LimitSELECT * FROM products WHERE MATCH(keywords) AGAINST('product1' IN BOOLEAN MODE) LIMIT 10,那么我什么也得不到。
我尝试使用更大的数字来限制SELECT * FROM products WHERE MATCH(keywords) AGAINST('product1' IN BOOLEAN MODE) LIMIT 100,它再次工作。
有人能告诉我怎么做吗?

最佳答案

很久以前,我读过一些关于全文索引实现的文章。有些索引引擎只是将删除的记录标记为已删除,而不是从索引中删除,这些已删除的项目可以被索引搜索操作命中,并在返回给用户之前从最终结果中删除。
因此,如果mysql以这种方式工作,那么我使用LIMIT with MATCH,mysql可能只是搜索索引的最开始部分以获得更好的性能。但是这些行已经被删除了,所以我得到的结果是空的。
然后我做了这些,结果证明了这一点:
创建一个测试表,使用与我在问题部分发布的查询完全相同的查询。
插入两行:id:1,关键字:product1,id:2,关键字:product2。
运行搜索查询:SELECT * FROM products WHERE MATCH(keywords) AGAINST('product1' IN BOOLEAN MODE) LIMIT 1,然后得到正确的结果。
删除所有这两条记录并再次插入。
从步骤3运行查询,然后我什么也没有得到。
但如果我运行:SELECT * FROM products WHERE MATCH(keywords) AGAINST('product1' IN BOOLEAN MODE) LIMIT 2,它将再次返回正确的结果。
所以现在,一个快速的解决方法是将匹配条件与另一个条件相结合。在这种情况下,mysql将获取比匹配阶段所需更多的信息。这个查询可以工作:SELECT * FROM products WHERE MATCH(keywords) AGAINST('product1' IN BOOLEAN MODE) AND id >= 0 LIMIT 1
我还对查询运行了explain,它还使用了关键字索引。
MySQL Doc(https://dev.mysql.com/doc/refman/5.6/en/innodb-fulltext-index.html)中的这些行也可能是关于这个问题的:
删除具有全文索引列的记录可能会导致辅助索引表中出现许多小的删除,从而使这些表的并发访问成为争论的焦点。为避免此问题,每当从索引表中删除记录时,已删除文档的文档ID(DOC_ID)将记录在特殊的FTS_udeleted表中,并且索引记录将保留在全文索引中。在返回查询结果之前,将使用FTS\u DELETED表中的信息筛选出已删除的文档ID。这种设计的好处是删除既快又便宜。缺点是删除记录后索引的大小不会立即减小。要删除已删除记录的全文索引项,必须在innodb_OPTIMIZE_full text_only=on的索引表上运行OPTIMIZE TABLE以重新生成全文索引。有关更多信息,请参阅优化InnoDB全文索引。

09-07 23:09