【问题标题】:Why does MySQL not use an index on a int field that's being used as a boolean?为什么 MySQL 不在用作布尔值的 int 字段上使用索引?
【发布时间】:2008-12-24 15:15:10
【问题描述】:
select * from myTable where myInt

在解释查询时不会显示任何可能的键,即使 myInt 字段上有索引。

编辑:
有问题的索引不是唯一的。

【问题讨论】:

    标签: mysql indexing


    【解决方案1】:

    要让 MySQL 使用索引,您必须明确地将 int 字段与一个值进行比较(例如 true、1)。

    select * from myTable where myInt = true
    

    【讨论】:

      【解决方案2】:

      我不是数据库专家,但如果字段只有两个可能的值,是否会破坏在字段上建立索引的目的?

      如果索引列中的所有字段都是唯一的,那么数据库引擎可以进行索引扫描以查找相关行。如果只有两个可能的值 - 那么我看不到将该字段编入索引的目的。数据库引擎必须执行与索引不存在时相同的操作。

      也许 MySQL 没有将它显示为可能的键,因为引擎已经放弃了在执行计划中使用索引的想法?

      【讨论】:

      • 索引不限于唯一列。索引基本上是根据索引中的列进行排序/散列的查找表。索引的目的是告诉 RDMS 优化对表中某些列的搜索。布尔索引可能对性能影响不大,但它是有效的。
      • 对,我不是在问它是否有效,我是在问它是否有用。被索引的字段将永远只有 0 或 1,因此索引将包含两个条目,每个条目中有 N / 2 行,其中 N = 表的大小。正确的?那么索引这个字段有什么意义呢?
      • @matt b:基数并不决定特异性。假设该字段仅在一小部分时间设置为 1:如果您只想选择那些行,那么全表扫描将是愚蠢的。
      【解决方案3】:

      有很多因素需要考虑。

      一个不应该参与其中的因素是问题中使用的符号。当列是布尔值时,优化器应将这些条件视为相同:

      SELECT * FROM MyTable WHERE MyInt;
      
      SELECT * FROM MyTable WHERE MyInt != 0;
      
      SELECT * FROM MyTable WHERE MyInt IS TRUE;
      
      SELECT * FROM MyTable WHERE MyInt = TRUE;
      

      可能还有其他等效的公式。其中第一个不是标准 SQL(即使 MyInt 的类型是 BOOLEAN;其他都是标准的。但是优化器应该简单地将速记转换为适当的长格式,然后表现得与长格式是由(如果优化器不这样做,那么可以说优化器存在问题;在决定如何处理查询之前,应该将查询简化为规范形式。但是,即使是最好的优化器也经常存在盲点. 学习如何避免这些是一种艺术形式,并且本质上是 DBMS 特有的。)

      当优化器认为索引会提高查询性能时,它会使用索引。当索引不会提高性能时,它会被忽略(如果优化器有任何好处)。有时,这取决于索引的统计信息是否是最新的。

      在数据仓库系统中,系统可以设计和配置为非常快速地对表进行顺序扫描;在这样的系统中,如果索引的选择性使得使用它会提取超过 25% 的行,那么执行全表扫描实际上比使用索引更快。

      考虑一下。通过索引读取时,DBMS 必须至少进行两次读取;它从索引页读取行的信息,然后它必须从数据页读取行。

      一些 DBMS 提供仅索引表。所有数据都在索引中。其他 DBMS 提供了一种机制,您可以说“索引在 A、B、C 列上是唯一的;但是,在数据中也包括 D 和 E 列”。然后,如果查询需要来自 A、B、C、D 或 E(或任何组合)的数据,并且没有对其他列进行过滤,则 DBMS 只需扫描索引,而不是表页。

      通常,您会在一个页面中获得许多索引行。但是,对于某些表,读取索引可能需要读取比读取行更多的数据。考虑包含两个(4 字节)整数 ID 值的原型多对多映射表。这需要数据页中每行 8 个字节,但索引可能需要 4-8 个字节的开销(因为索引键条目存储了两个 ID 值以及在磁盘上定位相应行所需的信息)。因此,那里的索引扫描可能涉及两倍于数据扫描的磁盘 I/O,即使索引扫描是“仅索引”完成的。

      这只是触及使用或不使用索引的可能原因的表面。

      【讨论】:

        【解决方案4】:

        在我看来,您的问题的 SQL 格式不正确。您是否正在寻找列的非空值?这应该使用索引:

        select * from myTable where myInt is not null
        

        【讨论】:

        • MySQL 将任何非零/空表达式评估为真,因此例如语句“SELECT * FROM myTable WHERE 1”是有效语句,并将返回表中的所有记录。在 myInt 字段中,我存储 0 或 1,而不是 NULL 和 NOT NULL 值。
        • @eagle:您正在存储两个不同的非空值(0 和 1)。 MySQL 允许你使用非标准的缩写;如果您使用速记,您的 SQL 将不会轻易迁移到其他 DBMS。
        猜你喜欢
        • 2019-08-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-23
        • 2011-07-23
        • 2013-05-23
        • 1970-01-01
        • 2016-12-22
        相关资源
        最近更新 更多