【问题标题】:How do relational databases fetch the unindexed columns?关系数据库如何获取未索引的列?
【发布时间】:2013-03-22 10:12:45
【问题描述】:

我的问题与关系数据库访问数据的方式有关,以及使用仅索引扫描的特殊情况,即检查所有“位置”条件并从某个索引获取所有返回值的扫描,而不访问表本身.

  1. 假设我们需要访问一些不在索引中的列。我们需要出于以下两个原因之一(或两者)访问它们:与“where”子句进行比较并获取列值作为结果。在这种情况下,数据库将如何操作:它会获取整行,还是只获取它需要的列?

  2. 作为第一个问题的结果出现了这个问题:如果我们不使用仅索引扫描,选择查询中返回的列数真的很重要吗?我的意思是,如果我们必须获取或与 'where' 子句比较某些未索引的列 - 我们返回多少列真的很重要,或者我们可以编写“select * from ...”而不用担心数据库获取反正整行?

  3. 当我们使用 Index-Only-Scans 时,我们必须将查询处理的所有列包含在一个索引中。如果某个列包含在另一个索引中 - 这不会破坏性能。我说的对吗?

  4. 我读到 MySQL InnoDB 引擎默认使用聚集索引,即表中的所有行都按某个索引进行物理排序。这意味着使用某个二级索引搜索该表的效率会降低,因为在该搜索之后,db 必须在主索引上创建第二个,因为在聚集索引中,db 不再存储 rowId。我对吗?如果是,为什么 MySQL 会以这种方式实现索引,从而限制二级索引的使用?

【问题讨论】:

    标签: mysql sql indexing


    【解决方案1】:

    其中一些解释可能会涵盖您已经知道的内容,但完整的细节可能会对未来的读者有所帮助。

    1. 服务器很可能只获取所需的行。但是,这可能会受到数据存储方式的影响。例如,InnoDB 引擎通常会存储大数据(例如 TEXTs 和 BLOBs 离页,因此如果不需要,可能不会获取这些数据。

    2. 我想我需要在这里澄清一下,如果我在您的问题中遗漏了什么,请纠正我。首先,最好只返回您需要的列并列出所有列而不是选择* 更快。与 #1 一样,选择其他列会有多大的不同取决于。选择大列(如TEXTs 或BLOBs)通常比小列更昂贵。

    3. 我不是 100% 确定你在这里的意思,但我想我可以回答这个问题。如果您有像SELECT c1, c2, c3 FROM table WHERE c1 = 1 AND c2 = 2 这样的查询,那么像(c1,c2,c3) 这样的索引可能是最佳的;查询需要的所有列都在索引中,因此服务器不需要查找完整的数据行。 c1c2c3 是否包含在任何其他索引中都没有关系。

    4. 在您的问题中,您说的是a clustered index db is not storing the rowId anymore,这并不完全正确。

      假设 rowId 是数据的唯一标识符,可能是数字标识符:

      在非聚集数据库表中,所有索引都将某些列连接到物理数据位置。在主索引的情况下,这看起来像rowId -> data location。二级索引可能类似于column 1 -> column 2 -> data location。为了获取任何其他数据,服务器然后根据物理位置查找数据。

      在聚簇表中,物理数据基本上是主索引。主索引类似于rowId -> data,二级索引类似于column 1 -> column 2 -> rowId

      对于非聚集表,完整的查找路径类似于使用主索引的rowId -> data location -> data 和使用二级索引的column 1 -> column 2 -> data location -> data

      对于聚簇表,主索引类似于 rowId -> data,二级索引类似于 column 1 -> column 2 -> rowId -> data

      因此,为了更正本节开头的引用,真正“存储”rowId 的唯一索引是聚簇表上的二级索引。

      虽然在聚簇表上的二级索引查找比在非聚簇表上要慢,但如果您使用的是短主键,则差异通常可以忽略不计。聚簇表的主要好处之一是主索引查找速度更快,因此如果您主要使用主键查找,它们是有益的。

    响应 KutaBeach 的 cmets:

    获取不需要的列没有帮助。当服务器需要获取数据以获取不在索引中的行时,它并不总是获取该行的所有数据。一些存储配置将一些数据存储在主行之外,因为它可能非常大,否则会影响性能。例如,TEXT 列的每行长度为 65535 个字符。如果存储引擎将该数据存储在页面外,那么在不需要 TEXT 列的情况下,从行中获取数据会快得多。

    听起来rowId 是指行的物理地址,而不是分配给每一行的唯一编号。在这种情况下,您是正确的,只有聚集表上的二级索引不存储rowId;所有其他索引都存储rowId。然而,这并不是因为数据可以或不能移动;表中的数据可以随时移动,在这种情况下,索引会更新以反映移动。在 MySQL 中,PRIMARY INDEX 基本上只是表的主索引。它与UNIQUE 索引几乎相同,因为它强制值是唯一的,唯一的区别是它用作表的主键。非聚集索引确实包含每个rowId

    【讨论】:

    • 非常感谢,G-Nugget!以下是对我的问题的一些澄清:2)如果DB无论如何都会读取整个行,为什么最好通过查询获取更少的列?看起来对于 DB 没有区别。
    • 4) 我不明白您为什么在非聚集表中谈论“主”索引。我认为在这些表中可以在任何列上创建索引,并且对其中任何一个都没有特殊处理。这些索引通常将某些列值与 rowId 连接起来,这可以将我们引导到数据所在的位置。所以他们有效地存储了所有的rowId。并且只有聚集表中的二级索引不存储 rowId,因为行可能会在聚集表中移动。我是对还是错?
    猜你喜欢
    • 2017-02-20
    • 1970-01-01
    • 2021-02-10
    • 2017-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-15
    • 1970-01-01
    相关资源
    最近更新 更多