何时和为什么数据库连接是昂贵的?

16 浏览
0 Comments

何时和为什么数据库连接是昂贵的?

我正在研究一些数据库问题,关注的是关系型数据库的一些局限性。

我发现连接大型表格非常耗费资源,但我并不完全明白原因。数据库管理系统需要执行什么操作来执行连接运算,瓶颈在哪里?

如何通过反规范化来应对这种开销?其他优化技术(如索引)如何帮助解决这个问题?

欢迎分享个人经验!如果您要发布资源链接,请避免使用维基百科。我已经知道在哪里可以找到。

在此,我想了解BigTable和SimpleDB等云服务数据库使用的反规范化方法。请参见此问题

admin 更改状态以发布 2023年5月23日
0
0 Comments

大多数评论者忽略了复杂关系型数据库中可用的各种连接方法,而去反复强调去规范化数据的维护成本更高的问题。并不是每个连接都基于索引,数据库有很多优化的算法和连接方法,旨在降低连接成本。

无论如何,连接的成本取决于其类型和其他一些因素。它甚至可以非常便宜,以下是一些示例:

  • 哈希连接,在其中大量数据被均匀连接,成本非常便宜,只有当哈希表无法缓存在内存中时成本才会变得显著。不需要索引。加入数据集的等分可能会很有帮助。
  • 排序合并连接的成本取决于排序成本而不是合并 -- 基于索引的访问方法可以几乎消除排序成本。
  • 基于索引的嵌套循环连接的成本取决于b-tree索引的高度和表块本身的访问。它很快,但不适合大量连接。
  • 基于集群的嵌套循环连接要便宜得多,每个连接行需要更少的逻辑IO -- 如果加入表都在同一个集群中,那么通过加入行的合并变得非常便宜。

数据库的设计目的就是连接,它们在如何连接方面非常灵活,通常非常高效,除非他们的连接机制出了问题。

0
0 Comments

反规范化以提高性能?听起来很有说服力,但却站不住脚。

克里斯·戴特和特德·科德博士一起提出了关系数据模型,他们厌倦了针对规范化的错误争论,并系统地使用科学方法进行了全面的解构:他拿了大型数据库并测试了这些说法。

我认为他在1988-1991年的《关系数据库写作》中写过关于这个的内容,但这本书后来被纳入第六版的《数据库系统概论》中,该书是关于数据库理论和设计的权威文本,我写作时已经是第八版,并有可能在未来几十年内仍在使用。克里斯·戴特在大多数人还是赤脚的时候,就成为了这个领域的专家。

他发现:

  • 其中一些适用于特定情况
  • 所有这些说法都不适合常规使用
  • 所有这些说法在其他特定情况下都显著更糟糕

这归结于减少工作集大小。涉及正确选择键和正确设置索引的连接是便宜的,而不是昂贵的,因为它们允许在行实现之前对结果进行重要剪枝。

实现结果涉及批量磁盘读取,这是整个过程中最昂贵的方面。相比之下,执行连接逻辑上仅需要检索键,实际上甚至没有获取键值:连接比较使用键哈希值,从而减轻了多列连接的成本,大大降低了涉及字符串比较的连接的成本。不仅更多信息可以适应缓存,还需要进行的磁盘读取要少得多。

此外,一个好的优化器会选择最严格的条件并在执行联接之前应用它,非常有效地利用具有高基数的索引上联接的高选择性。
承认这种类型的优化也可以应用于非规范化数据库,但通常想要非规范化模式的人不会在设置索引时想到基数。
重要的是要理解,在实践中很少进行表扫描(在生成连接过程中检查表中的每一行)。只有满足以下一项或多项条件时,查询优化器才会选择表扫描。

  • 关系中少于200行(此时扫描会更便宜)
  • 连接列上没有合适的索引(如果这些列上的连接有意义,为什么没有索引?让它修复)
  • 在比较列之前需要类型强制转换(WTF?让它修复或返回home)请参见ADO.NET问题的结尾注释
  • 比较的参数之一是表达式(没有索引)

执行一个操作比不执行它更昂贵。然而,执行错误的操作,被迫进行毫无意义的磁盘I / O,然后在执行实际需要的连接之前丢弃无用数据,这更加昂贵。即使“错误”的操作已经预先计算并且索引已经明智地应用,仍然存在显著的惩罚。非规范化以预先计算连接-尽管涉及更新异常-是对特定连接的承诺。如果需要不同的连接,这个承诺将花费您很大代价。如果有人想提醒我这是一个不断变化的世界,我想你会发现,更大的数据集和更强大的硬件只会夸大戴特的发现结果的差异。
对于你们所有从事计费系统或垃圾邮件生成器(你们真可耻)的人,如果你们气愤地开始打字告诉我,你们确切知道反范式化比规范化更快,那么很抱歉,但是你们只是处于特殊情况中——即,你们按顺序处理所有数据的情况。这不是一般情况,你们的策略是合理的。但你们不应该误导地加以推广。有关反范式化在数据仓库方案中适当使用的更多信息,请参见注释部分的结尾。
我还想回应一下以下内容:
"连接只是一些涂口红的笛卡尔积"
真是胡说八道。限制条件尽可能早地应用,最先使用最严格的限制条件。你读过理论,但你没有理解它。连接只被查询优化器视为"具有谓词的笛卡尔积",这实际上是一种符号表示(实际上是一种规范化),以促进符号分解,从而使优化器可以生成所有等效的转换,并根据成本和选择性对它们进行排名,以便选择最佳查询计划。
要让优化器生成笛卡尔积的唯一方法是未提供谓词:SELECT * FROM A,B

注:
大卫·奥德里奇提供了一些重要的附加信息。

实际上,除了索引和表扫描之外,还有许多其他策略,现代优化器在生成执行计划之前将对它们进行成本估算。

一个实用的建议: 如果它可以用作外键,则对其进行索引,以便优化器可以使用索引策略。

过去我是MSSQL优化器的智商,但两个版本之后就变了。现在它通常比我更聪明。从某种意义上来说,它是一个专家系统,将许多非常聪明的人在一个足够封闭的领域中所拥有的智慧编码成规则系统,这是有效的。


“胡说八道”可能有些不得体。有人要求我少点傲慢,提醒我数学是无所谓的。这是真的,但并不是所有数学模型的含义都应该字面理解。如果你小心地避免检查它们的荒谬性(里面有点双关语),并且在尝试解释你的方程之前一定要确保你将它们全部消除,负数的平方根非常方便。

我如此凶猛地回应的原因在于,原文说:

连接是笛卡尔积......

这也许不是作者的本意,但这就是他写的,而且明显是错误的。笛卡尔积是一个关系,而连接是一个函数。更具体地说,连接是一个关系值函数。在没有谓词的情况下,它会产生笛卡尔积,并检查它是否实现了这一点是数据库查询引擎的正确性检查之一,但在实践中没有人编写无限制的连接,因为除了课堂之外,它们没有任何实际价值。

我强调这点是因为我不希望读者陷入把模型与被模拟的事物混淆的陈旧陷阱中。模型是一种近似,是为了方便操作而故意简化的。


选择扫描表连接策略的切换可能因数据库引擎而异。它受到实现决策的影响,例如树节点填充因子、键值大小和算法的细微差别,但大体上高性能索引的执行时间为 k log n + c。C项是一个固定的开销,大部分由设置时间构成,而曲线的形状意味着与线性搜索相比,直到n达到几百,你才会得到回报。


有时候去规范化是个好主意

去规范化意味着对特定的连接策略进行了承诺。如前所述,这干扰了其他连接策略。但如果你有大量的磁盘空间、可预测的访问模式,并且倾向于处理其中大部分或全部的数据,那么预先计算连接可能非常值得。

你还可以找出你的操作通常使用的访问路径,并为这些访问路径预先计算所有连接。这是数据仓库的前提条件,或者至少是在由知道自己在做什么的人构建的数据仓库中,在不只是为了遵守流行词的标准。

一个经过适当设计的数据仓库是通过一个规范化的事务处理系统的大量转换周期性地产生的。这种操作和报告数据库的分离具有非常理想的效果,可以消除OLTP和OLAP(在线事务处理即数据输入,和在线分析处理即报告)之间的冲突。

这里的一个重要点是,除了定期更新之外,数据仓库是只读的。这使得更新异常问题无效。

不要犯将OLTP数据库(数据录入的数据库)范式化的错误。这可能会加快账单运行速度,但如果您这样做,就会出现更新异常。尝试让《读者文摘》停止给您发送杂志了吗?

现在磁盘空间很便宜,所以开心去使用吧。但是范式化只是数据仓库的一部分。更大的性能提升来自于预计算的汇总值:如每月总计等等。总是试图减少工作集。


ADO.NET类型不匹配的问题

假设您有一个包含索引列的SQL Server表,该列的类型为varchar,并且您使用AddWithValue传递一个参数约束查询该列的内容。C#字符串是Unicode,因此推断的参数类型将为NVARCHAR,这不符合VARCHAR。

VARCHAR转NVARCHAR是一种扩展转换,因此它会被隐式地执行-但是再见索引,祝您好运去解决问题。


“计算磁盘访问次数”(Rick James)

如果所有内容都在RAM中缓存, JOINs 相当便宜。也就是说,范式化没有太多性能惩罚。

如果“规范化”模式导致 JOINs 频繁访问磁盘,但等效的“非范式化”模式不必访问磁盘,则非范式化在性能竞赛中胜出。

原作者的评论:现代数据库引擎非常擅长组织访问顺序以在联接操作期间最大限度地减少缓存未命中。虽然上面的内容是正确的,但可能被误解为联接在大型数据上会导致问题的昂贵。这会导致缺乏经验的开发人员做出错误的决策。

抱歉,由于上下文缺失,无法确定需要翻译的内容。请提供更多上下文。

0