【问题标题】:Query speed based on order of columns基于列顺序的查询速度
【发布时间】:2011-01-03 06:22:20
【问题描述】:

数据库中列类型的顺序对查询时间有影响吗?

例如,具有混合排序(INT、TEXT、VARCHAR、INT、TEXT)的表的查询速度是否会比具有连续类型(INT、INT、VARCHAR、TEXT、TEXT)的表的查询速度慢?

【问题讨论】:

    标签: sql mysql postgresql


    【解决方案1】:

    答案是肯定的,它确实很重要,而且很重要,但通常并不重要。

    所有 I/O 都在页面级别完成(通常为 2K 或 4K,具体取决于您的操作系统)。行的列数据彼此相邻存储,除非页面已满,在这种情况下,数据将写入另一个(通常是下一页)页面。

    您选择的列(基于表定义)之间的列所需的磁盘数据空间越大,所选列的数据(有时)位于不同页面的可能性就越大。在不同的页面上可能会导致额外的 I/O 操作(如果在其他页面上没有选择其他行)。在最坏的情况下,您选择的每一列都可能位于不同的页面上。

    这是一个例子:

    create table bad_layout (
    num1 int,
    large1 varchar(4000),
    num2 int,
    large2 varchar(4000),
    num3 int,
    large3 varchar(4000)
    );
    
    create table better_layout (
    num1 int,
    num2 int,
    num3 int,
    large1 varchar(4000),
    large2 varchar(4000),
    large3 varchar(4000)
    );
    

    比较: 从 bad_layout 中选择 num1、num2、num3; 从better_layout中选择num1、num2、num3;

    因为对于 bad_layout 每个 num 列基本上将位于不同的页面上,所以每一行将需要 3 次 i/O 操作。相反,对于 better_layout,num 列通常会在同一页面上。

    bad_layout 查询可能需要大约 3 倍的时间来执行。

    良好的表布局会对查询性能产生很大影响。在表格布局中,您应该尽量让通常一起选择的列彼此靠近。

    【讨论】:

    • 有道理;有人愿意测试吗?我手边没有 PostgreSQL 安装。
    • TOAST 不会在很大程度上防止大列值导致此类问题吗?此外,该文档(如果我没看错的话)明确指出不允许行元组跨越多个页面。
    【解决方案2】:

    顺序不太重要。运行时间受磁盘访问次数等因素支配,磁盘访问次数和顺序不太可能因为对一行内的数据进行重新排序而改变。

    一个例外是如果您的行中有一个非常大的项目(比磁盘块大得多,通常是 4K?)。如果表中有一个非常大的列,您可能希望将其作为最后一列,这样如果您不访问它,则可能不需要完全分页。但即使那样,您也必须非常努力地生成一个数据集和访问模式,其中差异会很明显。

    【讨论】:

    • 实际上,我认为即使中间的“大”列不选择也不会产生影响。如果它很大,无论如何它都会被TOASTed。所以真正的列数据不会驻留在普通的表块中,如果没有选择该列,TOAST表也不会被触及
    【解决方案3】:

    在 PostgreSQL 中,如果您首先放置固定宽度的列,您将获得优势,因为该访问路径经过特别优化。所以 (INT, INT, VARCHAR, TEXT, TEXT) 将是最快的(VARCHAR 和 TEXT 的相对顺序无关紧要)。

    此外,如果您正确管理类型的对齐要求,则可以节省空间,从而提高吞吐量和性能。例如,(INT, BOOL, INT, BOOL) 将需要 13 个字节的空间,因为第三列必须在 4 字节边界处对齐,因此在第二列和第三列之间将浪费 3 个字节的空间.更好的是(INT,INT,BOOL,BOOL)。 (这行之后的内容可能还需要对齐至少 4 个字节,所以最后会浪费 2 个字节。)

    【讨论】:

    • 这很有趣,不知道。你对这个话题有什么参考吗?
    • 这主要来自我的源代码知识。如果您想深入了解,请查找fastgetattr
    • 我很想看到一个可以证明这一点的工作示例。这是否更多地基于代码存在差异,但在现实世界中您实际上不会注意到真正的差异类型的东西?也许有一些空闲时间我会玩一个例子并发布如果可以的话。
    【解决方案4】:

    我建议无论您如何排列列,绝对没有 [显着] 差异。

    PostgreSQL:http://social.msdn.microsoft.com/Forums/en-US/sqldatabaseengine/thread/a7ce8a90-22fc-456d-9f56-4956c42a78b0

    SQL 服务器: http://social.msdn.microsoft.com/Forums/en/sqldatabaseengine/thread/36713a82-315d-45ef-b74e-5f342e0f22fa

    我怀疑 MySQL 也是如此。

    所有数据都是在页面中读取的,因此如果您的数据适合单个页面,那么您如何对列进行排序并不重要。如果一个磁盘块大小为2K、4K,则需要多个来满足“8K页面请求”。如果磁盘块大小为 64K(对于大型数据库系统),则您已经在缓冲其他数据。

    不仅如此,如果请求一条记录,它通常会检索该记录的所有页面,如果数据跨越多个页面,则包括溢出到第 2 页和第 3 页。然后从检索到的数据中计算出这些列。 SQL Server 对页内数据有一个限制,大约为 8060 字节。任何较大的内容都存储在主数据页面之外,类似于 PostgreSQL 的 TOAST,如果不使用该列,则不会检索。 仍然列在顺序中的位置无关紧要。

    例如,在 SQL Server 中,多个位字段一起存储在位模式掩码中 - 这与您是否将列放在一起无关。我怀疑 MySQL 和 PostgreSQL 在优化空间方面会做很多相同的事情。

    注意:[重要] - 这种限定的唯一原因是,可能在从数据页中提取特定列时,将其放在开头会有所帮助,因为低级程序集调用不必在内存块中寻找很远。

    【讨论】:

      猜你喜欢
      • 2013-09-12
      • 2015-05-31
      • 2016-12-09
      • 2011-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-10
      • 1970-01-01
      相关资源
      最近更新 更多