【问题标题】:Why does the cardinality of an index in MySQL remain unchanged when I add a new index?为什么我添加新索引时 MySQL 中索引的基数保持不变?
【发布时间】:2010-10-19 19:50:10
【问题描述】:

我已将 FULLTEXT 索引添加到我的一个 MySQL 数据库表中,如下所示:

ALTER TABLE members ADD FULLTEXT(about,fname,lname,job_title);

问题是使用 phpmyadmin 我可以看到我的新索引的基数只有 1。这是否意味着永远不会使用索引?

我已经运行了一个分析表命令,但它似乎没有做任何事情。

analyze table members

索引字段的类型分别是varchar(100)、varchar(100)、text、varchar(200),使用的引擎是MyISAM,表大约有30000行,都是唯一的。我的 MySQL 版本是 5.0.45。

我是不是做错了什么?

【问题讨论】:

    标签: mysql indexing full-text-search cardinality


    【解决方案1】:

    如果表中只有 1 行,那么索引的基数当然应该是 1。它只是计算唯一值的数量。

    如果您将索引视为基于桶的查找表(如哈希),那么基数就是桶的数量。

    它的工作原理如下:当您在一组列(a,b,c,d) 上构建索引时,数据库会遍历表中的所有行,查看每行的这 4 列的有序四组。假设您的表格如下所示:

    a  b  c  d  e   
    -- -- -- -- --  
    1  1  1  1  200 
    1  1  1  1  300
    1  2  1  1  200
    1  3  1  1  200
    

    所以数据库查看的只是 4 列 (a,b,c,d):

    a  b  c  d  
    -- -- -- --
    1  1  1  1 
    1  2  1  1 
    1  3  1  1 
    

    看到只剩下 3 个唯一的行了吗?那些将成为我们的桶,但我们会回到那个。实际上,表中的每一行还有一个记录 ID 或行标识符。所以我们原来的表格是这样的:

    (row id) a  b  c  d  e   
    -------- -- -- -- -- --  
    00000001 1  1  1  1  200 
    00000002 1  1  1  1  300
    00000003 1  2  1  1  200
    00000004 1  3  1  1  200
    

    所以当我们只查看 (a,b,c,d) 的 4 列时,我们实际上也在查看行 id:

    (row id) a  b  c  d 
    -------- -- -- -- --
    00000001 1  1  1  1
    00000002 1  1  1  1
    00000003 1  2  1  1
    00000004 1  3  1  1
    

    但我们想通过 (a,b,c,d) 而不是按行 id 进行查找,所以我们生成如下内容:

    (a,b,c,d) (row id)
    --------- --------
    1,1,1,1   00000001
    1,1,1,1   00000002
    1,2,1,1   00000003
    1,3,1,1   00000004
    

    最后,我们将具有相同 (a,b,c,d) 值的行的所有行 ID 分组在一起:

    (a,b,c,d) (row id)
    --------- ---------------------
    1,1,1,1   00000001 and 00000002
    1,2,1,1   00000003
    1,3,1,1   00000004
    

    看到了吗? (a,b,c,d) 的值,即 (1,1,1,1) (1,2,1,1) 和 (1,3,1,1) 已成为我们查找表的键到原始表的行中。

    实际上,这一切都没有真正发生,但它应该让您很好地了解如何完成索引的“幼稚”(即直接)实现。

    但底线是:基数只是衡量索引中有多少唯一行。在我们的示例中,这是我们查找表中的键数,即 3。

    希望有帮助!

    【讨论】:

    • 感谢索引信息。很好解释。鉴于有 30000 行并且几乎每个成员都有不同的名称,我的索引的基数应该大于 1?
    • 感谢您对索引的解释,非常好,但您的解释没有回答上述问题。
    • 你说得对,我没有明确说出最终结论:我只是展示了 4 行落入 3 个桶中。我相信您可以发明另一行,该行可以添加到索引的现有 3 个存储桶之一中。这将使存储桶的数量保持不变,这也意味着索引的基数不变。对此感到抱歉。
    • 很好的解释。但是'实际上,这一切都没有发生'!?那么到底发生了什么……?我觉得有点困惑。
    • @PaulLo 好吧,以简单的方式实现的数据库引擎实际上可能会完成所有详细步骤。但我希望大多数实现会以不同的方式做到这一点 - 更有效地利用 RAM 和磁盘资源,以提供更低的延迟。
    【解决方案2】:

    我不能肯定地回答为什么 MySQL 不计算基数,但我可以猜到。 MySQL manual 声明:

    基数:对索引中唯一值数量的估计。这是通过运行 ANALYZE TABLE 或 myisamchk -a 来更新的。基数是根据存储为整数的统计信息计算的,因此即使对于小型表,该值也不一定准确。基数越高,MySQL 在进行连接时使用索引的机会就越大。

    FULLTEXT 索引仅在 MATCH ... AGAINST (...) 查询中使用,这会强制使用索引。如果这些字段上没有 FULLTEXT 索引,则 MATCH ... AGAINST 语法不起作用。

    我的猜测是没有计算基数,因为确实没有必要

    请注意,即使未设置基数,也可以对索引进行搜索。

    作为记录,ANALYZE TABLE foobar 语句似乎正确设置了基数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-21
      • 2020-07-23
      相关资源
      最近更新 更多