【问题标题】:How to retrieve column selectivity metadata in MySQL, without creating an index?如何在不创建索引的情况下在 MySQL 中检索列选择性元数据?
【发布时间】:2017-11-19 14:42:21
【问题描述】:

假设以下 SQL 查询:

SELECT col1,col2 from table where col1 > 5 and col2 > 8

我相信 MySQL 将无法使用相同的表索引在两列中查找,因为这两个条件都是范围条件。 因此,我试图了解在这种情况下确定要索引哪一列的最佳方法是什么(这可能是最具选择性的一种)。

是否可以通过某种方式访问​​ MySQL 元数据,以便识别列 A 或 B 是否更具选择性,而无需实际为这两个选项创建索引并查看基数信息?

编辑:澄清一下,目标是找到一种方法来做到这一点,即使对于在没有索引的情况下需要永远运行的查询(因此在这种情况下计算行数是不可能的)。

【问题讨论】:

    标签: mysql sql indexing sqlperformance


    【解决方案1】:

    请注意,您的查询只有 col1col2。这意味着INDEX(col1,col2)INDEX(col2,col1) 正在“覆盖”。 "覆盖提供了额外的提升,因为整个查询都可以在索引的 BTree 中执行。

    如果您在SELECT 列表中添加另一列,它将不再被覆盖。

    但问题是关于将列放在索引中的哪个顺序。 把它想象成一个二维数组。 col1 > 5 and col2 > 8 指的是该二维数组的右下角。 MySQL 基本上必须扫描数组的右“一半”或下“一半”,因为一维索引首先按行或列排序。

    优化的“新”“MRR”功能可能能够将精力集中在角落而不是一半。这是一种找出方法:

    add one index
    FLUSH STATUS;
    SELECT ...
    SELECT SESSION STATUS LIKE 'Handler%';
    drop that index
    

    现在用另一个索引重复。

    然后比较 Handler 的值。最大的数字表示被触及的索引(或数据)行数。

    更简单的答案

    如果查询中的列是col1col2,则添加INDEX(col1, col2)(以任意顺序)。

    如果涉及更多列,请添加INDEX(col1)INDEX(col2)。优化器在它们之间进行选择。

    【讨论】:

    • 感谢瑞克的回答。我实际上是在寻找一种方法来确定要添加的索引,而无需运行计数查询,也不添加索引并为每个索引“测试”。 MySQL 是否有任何我可以从它的元数据中获得的信息,可以让我做出那个决定?对于大型表和查询,添加和删除索引的试验和错误可能需要很长时间,尤其是在优化大量查询时。我正在寻找一种方法来避免这种情况,如果存在的话。
    • 2 个范围难以处理;我在我的答案中添加了一个“更简单的答案”。
    【解决方案2】:

    运行这个查询有问题吗?

    select count(*),
           sum(col1 > 5),
           sum(col2 > 8),
           sum( col1 > 5 and col2 > 8)
    from t;
    

    第二列和第三列之间取最小值的那个是最有选择性的。

    注意:将两列都放在索引中仍然有价值。 MySQL 应该能够为 where 子句使用第二个键,而无需在数据页中查找数据。

    【讨论】:

    • 我没有明确地写出来(只是编辑了问题),但我的目标是能够识别正确的索引,即使相关的 count(*) 查询在没有索引的情况下需要永远运行.我试图弄清楚 MySQL 的优化器是否以及如何做到这一点,并模仿相同的操作。
    • @Tomer - 多年来我一直在思考如何自动生成索引,但没有成功。我最好的是Cookbook
    猜你喜欢
    • 2022-01-21
    • 1970-01-01
    • 2023-01-30
    • 1970-01-01
    • 2011-01-24
    • 1970-01-01
    • 2013-09-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多