【问题标题】:Fulltext and composite indexes and how they affect the query全文索引和复合索引以及它们如何影响查询
【发布时间】:2012-09-07 18:31:09
【问题描述】:

就说我有一个如下查询..

SELECT 
    name,category,address,city,state
FROM
    table
WHERE 
    MATCH(name,subcategory,category,tag1) AGAINST('education')
AND 
    city='Oakland'
AND
    state='CA' 
LIMIT
    0, 10;

..我有一个fulltext 索引为name,subcategory,category,tag1 和一个composite 索引为city,state;这对这个查询是否足够好?只是想知道在将全文索引与 MATCH/AGAINST 混合使用时是否需要额外的东西。

编辑:我想了解的是,查询中但未在所选索引(全文索引)中编入索引的其他列会发生什么情况,上面的示例是 @ 987654327@ 和state。 MySQL 现在如何找到这些匹配的行,因为它不能使用两个索引(或者可以吗?) - 所以,基本上,我试图了解 MySQL 如何以最佳方式查找数据对于不在所选全文索引中的列,如果有什么我可以或应该做的事情来优化查询。

【问题讨论】:

    标签: mysql indexing full-text-search


    【解决方案1】:

    如果我理解您的问题,您就知道 MATCH AGAINST 使用您的 FULLTEXT 索引,并且您想知道 MySQL 如何应用 WHERE 子句的其余部分(即它是执行表扫描还是索引查找)。

    这是我对您的表的假设:它在某些 id 列和 FULLTEXT 索引上有一个 PRIMARY KEY。

    首先,MySQL 将从不将 FULLTEXT 索引用于城市/州 WHERE 子句。为什么?因为 FULLTEXT 索引仅适用于 MATCH AGAINST。请参阅第一组项目符号(不是目录项目符号)之后的段落中的here

    编辑:在您的情况下,假设您的表不仅有 10 行,MySQL 将为您的 MATCH AGAINST 应用 FULLTEXT 索引,然后对这些结果进行表扫描以应用城市/state 在哪里。

    那么如果你在城市和州上添加一个 BTREE 索引呢?

    CREATE INDEX city__state ON table (city(10),state(2)) USING BTREE;
    

    因为它是一个简单的选择,所以 MySQL 只能对这个查询使用 一个 索引。它将要么使用全文 BTREE。请注意,当我说一个索引时,我的意思是一个索引定义,而不是多部分索引中的一列。 Anwway,这就引出了一个问题,它使用哪一个?

    这取决于表格分析。 MySQL 将尝试估计(基于最后一个 OPTIMIZE TABLE 的表统计信息)哪个索引将修剪最多的记录。如果城市/州 WHERE 使您减少到 10 条记录,而 MATCH AGAINST 仅使您减少到 100,则 MySQL 将使用 city__state 索引 first 用于城市/州 WHERE,然后执行表扫描反对的比赛。

    另一方面,如果 MATCH_AGAINST 让您减少到 10 条记录,而城市/州 WHERE 让您减少到只有 1000 条,那么 MySQL 将首先应用 FULLTEXT 索引,然后对城市和州进行表扫描。

    底线是索引的基数。本质上,将进入您的索引的值有多独特?如果您的表中的每条记录都将城市设置为 Oakland,那么它就不是一个非常唯一的键,因此具有 city = 'Oakland' 并不会真正为您减少那么多记录的数量。在这种情况下,我们说您的 city__state 索引具有低基数

    因此,如果您的 FULLTEXT 索引中 90% 的单词是“John”,那么出于完全相同的原因,这也对您没有太大帮助。

    如果你能负担得起空间和 UPDATE/DELETE/INSERT 开销,我建议添加 BTREE 索引并让 MySQL 决定他想使用哪个索引。根据我的经验,他通常会很好地挑选合适的人。

    我希望这能回答你的问题。

    编辑:附带说明,确保为 BTREE 索引选择正确的大小(在我的示例中,我选择了 city 的前 10 个字符)。这显然会对基数产生巨大影响。如果你选择了城市(1),那么显然你会得到比城市(10)更低的基数。

    EDIT2:您在 EXPLAIN 中看到的索引修剪最多记录的 MySQL 查询计划(估计)。

    【讨论】:

      【解决方案2】:

      我认为您可以通过在查询中使用 EXPLAIN 轻松确定使用哪个索引。请检查this question 的已接受答案,它提供了一些关于如何解释EXPLAIN 输出的好资源。

      MySQL 现在如何找到这些匹配的行,因为它无法使用 两个索引

      可以:Can MySQL use multiple indexes for a single query? 另外,您应该阅读文档:How MySQL Uses Indexes

      【讨论】:

      • 感谢您的回答,但不是我正在寻找的信息类型;在我的例子中,我可以看到它使用了fulltext 索引,但是这会将查询的其余部分与索引有关吗?
      • 恐怕我不明白你在问什么。 MySQL 解释器可以根据某些规则选择要使用的索引。 EXPLAIN 查询应提供有关所有被考虑的索引的信息。
      • 米海,+1。 @Brett,请发布表结构(SHOW CREATE TABLE),并在您的查询中发布 EXPLAIN 的结果,这样我们也可以看到它......
      • @MihaiTodor 我已经编辑了我的问题并进一步阐述。发布解释的结果可能无济于事,但如果您仍然想看到它。
      • @Brett 请查看我对答案所做的编辑。我希望这可以澄清事情。如果您需要有关优化的提示,您需要与我们分享查询中涉及的表的数据库结构以及EXPLAIN 的输出(但也许您应该在一个新问题中这样做,因为它不会在这里得到很多关注)。
      【解决方案3】:

      前段时间我有类似的任务,我注意到 MySQL 可以在一个查询中使用 FULLTEXT 索引或任何其他索引/索引,但不能同时使用两者;我无法将 FULLTEXT 与任何其他索引混合。任何带有全文搜索的选择都将以这种方式工作:

      • 使用全文搜索选择子集
      • 从“Using where”子集中选择符合其他条件的记录

      所以您可以使用全文索引或任何其他索引(我无法通过 FORCE INDEX 或其他任何方式同时使用这两个索引)。

      我建议尝试同时使用全文和使用其他索引(即在 City 和 State 列上)并比较结果 - 它们可能会因数据库中的实际内容而异。

      就我而言,我发现在此类查询中强制使用常规(非全文)索引会产生更好的性能(因为我有非常多的行,大约 300 000 行,并且非全文条件匹配其中大约 1000 个)。

      我使用的是 MySQL 5.5.24

      【讨论】:

        猜你喜欢
        • 2011-04-24
        • 1970-01-01
        • 1970-01-01
        • 2011-02-19
        • 1970-01-01
        • 2022-12-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多