何时以及为什么数据库连接费用高昂?

我正在研究数据库,我正在研究关系数据库的一些局限性。

我觉得大桌子的连接非常昂贵,但我不完全确定为什么。 数据库管理系统需要做什么来执行连接操作,瓶颈在哪里?
反规范化如何帮助克服这一开支? 其他优化技术(如索引)如何提供帮助?

个人经验值得欢迎! 如果您要发布资源链接,请避开维基百科。 我知道哪里可以找到。

与此相关,我想知道BigTable和SimpleDB等云服务数据库使用的非规范化方法。 看到这个问题。


非规范化以提高性能? 这听起来很有说服力,但它不能保持水分。

Chris Todd与Ted Codd博士共同担任关系数据模型的原始支持者,他与耐心纠正错误论据,反对规范化,并使用科学方法系统地拆除它们:他获得了大型数据库并测试了这些断言。

我认为他是在1988-1991年的关系数据库着作中写下来的,但是后来这本书被编入数据库系统导论的第六版,这是关于数据库理论和设计的权威文本,在我编写并可能保留的第八版中在未来几十年的印刷中。 Chris Date是这个领域的专家,当时我们大多数人还在赤脚奔跑。

他发现:

  • 其中一些人持有特殊情况
  • 他们都没有付清一般用途
  • 对于其他特殊情况,他们都显着恶化
  • 这一切都是为了减轻工作集的大小。 包含正确设置索引的正确选择的键的连接便宜,并不昂贵,因为它们允许在行被实现之前对结果进行显着修剪。

    实现结果涉及批量磁盘读取,这是练习中最昂贵的一个方面,数量级。 相反,执行连接逻辑上只需要检索密钥。 在实践中,甚至没有提取关键值:关键哈希值用于连接比较,减轻了多列连接的成本,并从根本上降低了包含字符串比较的连接成本。 不仅会更适合缓存,还有更少的磁盘读取操作。

    此外,优秀的优化者会选择最严格的条件,并在执行连接之前将其应用,非常有效地利用连接的高选择性对高基数的索引。

    诚然,这种类型的优化也可以应用于非规范化数据库,但是那些希望对规范进行非规范化的人通常在设置索引时不会考虑基数。

    理解表扫描(在生成连接过程中检查表中的每一行)在实践中很少见。 查询优化器只有在以下一项或多项条件成立时才会选择表扫描。

  • 关系中的行数少于200行(在这种情况下,扫描将会更便宜)
  • 在连接列上没有合适的索引(如果加入这些列是有意义的,那么为什么他们没有索引?修复它)
  • 在比较列之前需要进行类型强制转换(WTF?!修复或回家)请参阅ADO.NET ISSUE的结束注释
  • 比较的一个参数是表达式(没有索引)
  • 执行操作比不执行操作要昂贵。 然而,执行错误的操作,被迫进入毫无意义的磁盘I / O,然后在执行您真正需要的连接之前丢弃渣滓,则要贵得多。 即使预先计算了“错误”的操作并且合理地使用了索引,仍然存在重大的损失。 非规范化以预先计算加入 - 尽管需要更新异常 - 是对特定加入的承诺。 如果你需要不同的加入,这个承诺会让你付出巨大的代价。

    如果任何人想提醒我这是一个不断变化的世界,我认为你会发现在较硬的硬件上的较大数据集只是夸大了Date的发现。

    对于所有从事计费系统或垃圾邮件发送器工作的人(耻辱于你),并且愤怒地设置手键盘来告诉我,你知道一个事实,即反规范化速度更快,抱歉,但你住在一个特殊的案例 - 具体来说,就是您按顺序处理所有数据的情况。 这不是一般情况,你的策略是合理的。

    你错误地概括它是没有道理的。 有关在数据仓库场景中适当使用非规格化的更多信息,请参阅注释部分的末尾。

    我也想回应

    加入只是笛卡尔产品与一些lipgloss

    什么是一大堆bollocks。 限制条件尽可能早,首先限制性最强。 你已经读过理论,但你还没有明白。 只有查询优化器才将联接视为“谓词所应用的笛卡尔产品”。 这是一种符号表示(实际上是一种标准化),以促进符号分解,因此优化器可以生成所有等效转换并按成本和选择性对它们进行排名,以便它可以选择最佳查询计划。

    唯一能让优化器生成笛卡儿积的方法是不能提供谓词: SELECT * FROM A,B


    笔记


    David Aldridge提供了一些重要的附加信息。

    除了索引和表扫描之外的确有很多其他策略,而现代优化器在制定执行计划之前将花费所有这些策略。

    一个实用的建议:如果它可以作为外键使用,那么索引它,这样优化器就可以使用索引策略。

    我曾经比MSSQL优化器更聪明。 这在之前改变了两个版本。 现在它通常教我。 在一个非常真实的意义上说,它是一个专家系统,将许多非常聪明的人的所有智慧都编纂在一个足够封闭的领域,以便基于规则的系统是有效的。


    “Bollocks”可能已经不合适。 我被要求不那么高傲,并提醒说数学不是谎言。 这是事实,但并不是所有的数学模型的含义都必须从字面上理解。 负数的平方根是非常方便的,如果你仔细地避免检查它们的荒谬(双关语),并确保你在尝试解释你的等式之前全部取消它们。

    我之所以这么野蛮地回答,是因为这句话是这样说的

    加入是笛卡尔产品...

    这可能不是什么意思,但它是写的,它是绝对不真实的。 笛卡尔产品是一种关系。 连接是一个功能。 更具体地说,联接是关系值函数。 使用空谓词会产生笛卡尔积,并且检查它是否是数据库查询引擎的正确性检查,但实际上没有人会写无约束的连接,因为它们在教室之外没有实际价值。

    我之所以这样说,是因为我不希望读者陷入将模型与所建模的事物混淆的古老陷阱。 模型是一个近似值,为了方便操作而故意简化。


    选择表扫描连接策略的截止点可能因数据库引擎而异。 它受许多实现决策的影响,如树节点填充因子,键值大小和算法的细微差别,但广义而言,高性能索引的执行时间为k log n + c。 C术语是一个固定的开销,主要由建立时间决定,曲线的形状意味着你没有得到回报(与线性搜索相比),直到n达到数百。


    有时,去标准化是一个好主意

    非规范化是对特定连接策略的承诺。 如前所述,这会干扰其他加入策略。 但是,如果您拥有磁盘空间,可预测的访问模式以及处理大部分或全部数据的趋势,那么预先计算连接可能非常值得。

    您还可以计算出您的操作通常使用的访问路径,并预先计算这些访问路径的所有连接。 这是数据仓库背后的前提,或者至少它是由知道他们为什么要做他们在做什么的人创建的,而不仅仅是为了流行语的合规性。

    设计合理的数据仓库是通过大规模转换生成规范化交易处理系统的。 操作和报告数据库的这种分离具有消除OLTP和OLAP(在线事务处理即数据输入和在线分析处理即报告)之间的冲突的理想效果。

    这里重要的一点是,除了定期更新外,数据仓库是只读的。 这使得更新异常的问题没有意义。

    不要犯规格化你的OLTP数据库(发生数据输入的数据库)的错误。 计费运行可能会更快,但如果你这样做,你会得到更新异常。 曾试图让读者文摘停止发送你的东西?

    磁盘空间现在很便宜,所以请自行解决。 但denormalising只是数据仓库故事的一部分。 从预先计算的汇总值中可以获得更大的性能收益:每月总计,诸如此类的事情。 它始终是关于减少工作集。


    类型不匹配的ADO.NET问题

    假设您有一个SQL Server表,其中包含varchar类型的索引列,并且您使用AddWithValue传递约束此列上查询的参数。 C#字符串是Unicode,因此推断的参数类型将是NVARCHAR,它与VARCHAR不匹配。

    VARCHAR到NVARCHAR是一个扩大的转换,所以它隐式发生 - 但告别索引,并祝你好运找出原因。


    “盘点盘面”(里克詹姆斯)

    如果所有内容都缓存在RAM中, JOINs便宜。 也就是说,规范化没有太多的性能损失。

    如果一个“规范化”模式导致JOINs很多地击中磁盘,但是等效的“非规范化”模式不必击中磁盘,那么非规范化就赢得了性能竞争。

    来自原作者的评论:现代数据库引擎非常擅长组织访问次序,以最大限度地减少连接操作期间的缓存未命中。 上述情况虽然属实,但可能会被误解为暗示连接在大数据上的成本一定会很高。 这会导致缺乏经验的开发人员做出糟糕的决策。


    大多数评论者都没有注意到复杂RDBMS中可用的各种连接方法,而非规范化器总是掩盖了维护非规范化数据的较高成本。 并非每个连接都基于索引,并且数据库有许多优化的算法和连接方法,旨在降低加入成本。

    无论如何,加入的成本取决于其类型和其他一些因素。 它根本不需要昂贵 - 一些例子。

  • 散列数据是等间距的,散列连接确实非常便宜,而且如果散列表不能被缓存在内存中,代价才会变得显着。 不需要索引。 在连接的数据集之间进行Equi分区可能会有很大的帮助。
  • 排序合并连接的成本由排序的成本而非合并驱动 - 基于索引的访问方法几乎可以消除排序的成本。
  • 在索引上嵌套循环连接的成本由b-tree索引的高度和表格块本身的访问驱动。 它很快,但不适合批量连接。
  • 基于集群的嵌套循环连接要便宜得多,每个连接行需要更少的逻辑IO(如果连接的表都在同一个集群中,那么通过连接的行的连接,连接变得非常便宜)。
  • 数据库被设计为连接,并且它们在如何实现它们方面非常灵活,并且通常非常高效,除非它们使连接机制错误。


    我认为整个问题都是基于一个错误的前提。 加入大桌子不一定很贵。 事实上, 有效地进行连接是关系数据库完全存在的主要原因之一 。 大集合上的连接通常很昂贵,但很少要将大表A的全部内容与大表B的全部内容结合起来。而是编写查询,以便只使用每个表的重要行,并且由连接保持的实际集合保持较小。

    另外,您可以获得Peter Wone提到的效率,这样只有每个记录的重要部分都需要在内存中,直到最终结果集被实现。 另外,在有许多连接的大型查询中,您通常希望从较小的表集合开始,然后逐步扩展到较大的表集,以便尽可能保持存储集尽可能小。

    正确完成后,连接通常是比较,组合或过滤大量数据的最佳方式。

    链接地址: http://www.djcxy.com/p/37945.html

    上一篇: When and why are database joins expensive?

    下一篇: What's the best strategy for unit