数据库连接何时以及为何昂贵?

2024-03-08

我正在对数据库进行一些研究,并且正在研究关系数据库的一些局限性。

我发现大表的连接非常昂贵,但我不完全确定为什么。 DBMS需要做什么来执行连接操作,瓶颈在哪里?
非规范化如何帮助克服这种费用?其他优化技术(例如索引)有何帮助?

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

与此相关,我想知道 BigTable 和 SimpleDB 等云服务数据库使用的非规范化方法。看这个问题 https://stackoverflow.com/questions/176131/pros-of-databases-like-bigtable-simpledb.


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

Chris Date 与 Ted Codd 博士一起是关系数据模型的最初支持者,他对反对标准化的错误论点失去了耐心,并使用科学方法系统地推翻了它们:他拥有大型数据库和tested这些断言。

我认为他写在1988-1991 年关系数据库著作但这本书后来被编入了第六版数据库系统简介,即the关于数据库理论和设计的权威文本,在我撰写时已是第八版,并且可能在未来几十年内继续印刷。当我们大多数人还赤脚奔跑时,克里斯·戴特(Chris Date)就是这个领域的专家。

他发现:

  • 其中一些适用于特殊情况
  • 所有这些都无法满足一般用途
  • 对于其他特殊情况,所有这些都明显更糟

这一切都归结于减小工作集的大小。涉及正确选择的键和正确设置的索引的连接是便宜的,而不是昂贵的,因为它们允许对结果进行显着的修剪before这些行被具体化了。

实现结果涉及批量磁盘读取,这是该练习中成本最高的一个数量级。相比之下,执行连接在逻辑上只需要检索keys。实际上,甚至不获取键值:键哈希值用于连接比较,减轻多列连接的成本,并从根本上降低涉及字符串比较的连接成本。不仅会更适合缓存,而且需要执行的磁盘读取也会少得多。

此外,一个好的优化器会选择最严格的条件并在执行连接之前应用它,非常有效地利用高基数索引上连接的高选择性。

诚然,这种类型的优化也可以应用于非规范化数据库,但是那些人want当(如果)他们设置索引时,非规范化模式通常不会考虑基数。

重要的是要理解表扫描(在生成连接的过程中检查表中的每一行)在实践中很少见。仅当满足以下一项或多项条件时,查询优化器才会选择表扫描。

  • 关系中的行数少于 200(在这种情况下,扫描会更便宜)
  • 连接列上没有合适的索引(如果连接这些列有意义,那么为什么它们没有索引?修复它)
  • 在比较列之前需要进行类型强制(WTF?!修复它或回家)请参阅 ADO.NET 问题的末尾注释
  • 比较的参数之一是表达式(无索引)

执行某项操作比不执行该操作的成本更高。然而,执行wrong操作,被迫进行无意义的磁盘 I/O,然后在执行您真正需要的连接之前丢弃糟粕,是much更贵。即使预先计算了“错误”的操作并且合理地应用了索引,仍然存在显着的惩罚。非规范化以预先计算连接(尽管会带来更新异常)是对特定连接的承诺。如果您需要一个不同的加入,这个承诺会让你付出代价big.

如果有人想提醒我这是一个不断变化的世界,我想你会发现更糟糕的硬件上更大的数据集只会夸大 Date 发现的传播范围。

对于所有从事计费系统或垃圾邮件生成器工作的人(为你们感到羞耻),并愤怒地把手放在键盘上告诉我,你们知道非规范化更快的事实,抱歉,但你们生活在一个特殊的环境中。案例 - 具体来说,您处理的案例all的数据,按顺序。这不是一般情况,而且你are你的策略是合理的。

You are not错误地概括它是合理的。有关在数据仓库场景中适当使用标准化的更多信息,请参阅注释部分的末尾。

我也想回复一下

连接只是带有一些唇彩的笛卡尔积

真是一堆废话。尽早实施限制,最严格的首先实施。你读过这个理论,但你还没有理解它。连接是treated作为“谓词适用的笛卡尔积”only由查询优化器。这是一种符号表示(实际上是标准化),以促进符号分解,以便优化器可以生成所有等效的转换,并按成本和选择性对它们进行排序,以便可以选择最佳查询计划。

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


Notes


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

除了索引和表扫描之外,确实还有多种其他策略,现代优化器将在生成执行计划之前将它们全部消耗掉。

一个实用的建议:如果它可以用作外键,那么就对其进行索引,这样索引策略就是可用的给优化器。

我曾经比MSSQL优化器更聪明。两个版本前就改变了。现在一般都教me。从真正的意义上来说,它是一个专家系统,将许多非常聪明的人的所有智慧编入一个足够封闭的领域,使得基于规则的系统是有效的。


“胡说八道”可能有些不机智。他们要求我不要那么傲慢,并提醒我数学不会说谎。这是事实,但并非数学模型的所有含义都必须从字面上理解。如果你小心地避免检查它们的荒谬性(双关语),并确保在尝试解释方程之前将它们全部取消,那么负数的平方根会非常方便。

我之所以做出如此野蛮的回应,是因为该声明的措辞是这样的:

Joins are笛卡尔积...

这可能不是本意,但它is所写的内容,绝对是不真实的。笛卡尔积是一种关系。连接是一个函数。更具体地说,连接是关系值函数。使用空谓词,它将产生笛卡尔积,检查它是否这样做是对数据库查询引擎的正确性检查,但在实践中没有人编写无约束连接,因为它们在课堂之外没有实际价值。

我之所以这么说,是因为我不想让读者陷入将模型与建模对象混淆的古老陷阱。模型是一种近似值,是为了方便操作而故意简化的。


表扫描连接策略选择的截止点可能因数据库引擎而异。它受到许多实现决策的影响,例如树节点填充因子、键值大小和算法的微妙之处,但一般来说,高性能索引的执行时间为k log n + c。 C 项是固定开销,主要由设置时间组成,并且曲线的形状意味着您不会获得回报(与线性搜索相比),直到n有数百个。


有时非规范化是个好主意

非规范化是对特定连接策略的承诺。如前所述,这会干扰other加入策略。但是,如果您拥有大量磁盘空间、可预测的访问模式,并且倾向于处理大部分或全部磁盘空间,那么预先计算联接可能非常值得。

您还可以找出您的操作通常使用的访问路径,并预先计算这些访问路径的所有联接。这是数据仓库背后的前提,或者至少当它们是由那些知道为什么要做他们正在做的事情的人构建的,而不仅仅是为了遵守流行语时。

正确设计的数据仓库是通过标准化事务处理系统的批量转换定期生成的。操作和报告数据库的这种分离具有消除OLTP和OLAP(在线事务处理,即数据输入和在线分析处理,即报告)之间的冲突的非常理想的效果。

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

不要错误地对 OLTP 数据库(发生数据输入的数据库)进行非规范化。计费运行可能会更快,但如果这样做,您将收到更新异常。曾经尝试过让《读者文摘》停止向您发送内容吗?

如今磁盘空间很便宜,因此请淘汰自己。但非规范化只是数据仓库故事的一部分。更大的性能提升来自于预先计算的汇总值:每月总计,诸如此类的事情。它是always关于减少工作集。


ADO.NET 类型不匹配问题

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

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


“计算磁盘点击次数”(里克·詹姆斯)

如果所有内容都缓存在 RAM 中,JOINs相当便宜。也就是说,归一化没有太多作用绩效惩罚.

如果“规范化”模式导致JOINs大量访问磁盘,但等效的“非规范化”模式不必访问磁盘,那么非规范化就赢得了性能竞争。

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数据库连接何时以及为何昂贵? 的相关文章

  • 如何避免连接两个表时重复

    Student Table SID Name 1 A 2 B 3 C Marks Table id mark subject 1 50 physics 2 40 biology 1 50 chemistry 3 30 mathematics
  • 如何正确设计数据库的这一部分(循环引用?)

    情况 一个公司有很多项目一个项目有很多标签一个项目只属于1家公司一个标签可以属于多个项目公司必须有权访问自己的标签 示例1 在第一张图片中 公司的所有标签都可以通过projects project tag 获得 但如果所有项目都被删除 那么
  • 快速像素绘图库

    我的应用程序以每像素的方式生成 动画 因此我需要有效地绘制它们 我尝试过不同的策略 库 但结果并不令人满意 尤其是在更高分辨率的情况下 这是我尝试过的 SDL 好的 但是慢 OpenGL 像素操作效率低下 xlib 更好 但仍然太慢 svg
  • 要做或不做:将图像存储在数据库中[重复]

    这个问题在这里已经有答案了 在 Web 应用程序的上下文中 我的前老板总是说在数据库中放置对图像的引用 而不是图像本身 我倾向于同意在数据库中存储 url 与图像本身是一个好主意 但在我现在工作的地方 我们在数据库中存储大量图像 我能想到的
  • 如何更改phpmyadmin MySQL的IP地址?

    我在 xampp 中更改了 apache 的 IP 地址 但无法连接到 MySQL 我认为问题是我的 apache 不在我的数据库的同一网络上 我的 apache 位于 192 168 1 10 而我的 MySQL 位于 127 0 0 1
  • UITableView 由于阴影和边框而滞后

    我有以下代码来向 UITableViewCell 的背景添加边框颜色和阴影 我的问题是这段代码会导致 tableView 本身出现巨大的滞后 请你告诉我如何优化我的代码 防止 UITableView 的滞后 if cell viewWith
  • 计算元组中与模式匹配的元素

    我有一个矩阵m我想计算零的数量 m 2 0 2 2 4 4 5 4 0 9 4 8 2 2 0 0 我当前的代码如下 def zeroCount M return item for row in M for item in row coun
  • 如何在基于其他数据帧的数据帧中创建联接?

    我有 2 个数据框 一份包含学生批次详细信息 另一份包含分数 我想加入 2 个数据框 数据框1包含 s1 s2 s3 Stud1 Stud2 Stud3 Stud2 Stud4 Stud1 Stud1 Stud3 Stud4 数据框2包含
  • 如何在 Sequelize 现有模型中添加列?

    我使用此命令添加了模型和迁移文件 node modules bin sequelize model generate name User attributes firstName string lastName string email s
  • PDO获取最后插入的ID

    我有一个查询 我想获取插入的最后一个 ID 字段ID是主键并且自动递增 我知道我必须使用这个声明 LAST INSERT ID 该语句适用于如下查询 query INSERT INTO cell place ID VALUES LAST I
  • JPA中如何连接多个数据库?

    我有一个 Spring Boot 应用程序 当前使用 JPA 连接到单个数据库 application properties 文件中的连接详细信息 spring datasource url jdbc oracle thin localho
  • 改进C++逐行读取文件的能力?

    我正在解析大约 500GB 的日志文件 我的 C 版本需要 3 5 分钟 我的 Go 版本需要 1 2 分钟 我正在使用 C 的流来流式传输文件的每一行以进行解析 include
  • 在 Python 中,如果我有 unix 时间戳,如何将其插入 MySQL 日期时间字段?

    我正在使用 Python MySQLDB 我想将其插入 Mysql 中的 DATETIME 字段 我该如何使用cursor execute 来做到这一点 要将 UNIX 时间戳转换为 Python 日期时间对象 请使用datetime fr
  • Mono 实现 CLR 吗?或者至少有一些非托管的内部调用?或无?

    我们知道 C 使用非托管代码 如 P Invoke 或 CLR 实现的代码 如 InternalCall 我想知道的是 mono 它自己实现了一个完整的 CLR 还是只是一些非托管代码或者什么都没有 我可以使用 Net Reflactor或
  • where 子句中的双 %% ?

    我有一个 where 子句 如下例所示 WHERE subject LIKE chef AND dep LIKE psy 使用 1 或 2 符号有什么区别 我知道其中一个的含义 通配符 但不知道第二个添加的功能是什么 该查询可能是一个拼写错
  • 在python中将数据库表写入文件的最快方法

    我正在尝试从数据库中提取大量数据并将其写入 csv 文件 我正在尝试找出最快的方法来做到这一点 我发现在 fetchall 的结果上运行 writerows 比下面的代码慢 40 with open filename a as f writ
  • LEFT JOIN 比 INNER JOIN 快得多

    我有一张桌子 MainTable 有超过 600 000 条记录 它通过第二个表连接到自身 JoinTable 在父 子类型关系中 SELECT Child ID Parent ID FROM MainTable AS Child JOIN
  • 数据库分区 - 水平与垂直 - 规范化和行拆分之间的区别?

    我试图理解不同的概念数据库分区这就是我的理解 水平分区 分片 将表拆分为不同的表 其中将包含初始表中的行的子集 如果按大陆拆分用户表 我见过很多这样的示例 例如北美的子表 欧洲的另一个子表 ETC 每个分区位于不同的物理位置 理解 机器 据
  • 索引在 NOT IN 或 <> 子句中起作用吗?

    我读过 至少 Oracle 数据库中的普通索引基本上是 B 树结构 因此存储处理适当根节点的记录 小于 根的记录被迭代地存储在树的左侧部分 而 大于 根的记录被存储在右侧部分 正是这种存储方法有助于通过树遍历实现更快的扫描 因为深度和广度都
  • 记录类名、方法名和行号的性能影响

    我正在我的 java 应用程序中实现日志记录 以便我可以调试应用程序投入生产后可能出现的潜在问题 考虑到在这种情况下 人们不会奢侈地使用 IDE 开发工具 以调试模式运行事物或单步执行完整代码 因此在每条消息中记录类名 方法名和行号将非常有

随机推荐

  • Process.start() 启动的进程返回错误的进程 ID?

    我正在使用以下代码启动可执行文件 Process proc new Process proc StartInfo FileName executablePath proc Start proc WaitForInputIdle 在这次通话之
  • 使用 Process、RegistryKey 将 .NET Framework 代码移植到 .NET Standard

    我有一个来自现有 NET Framework 项目的方法 该方法从注册表获取 Windows 中默认浏览器的路径 并使用Process call string browser RegistryKey regKey null try regK
  • 请参阅调试目的的 Firebase 网络流量

    我希望能够使用 Charles Proxy 调试 firebase 分析 我无权访问源代码 因此无法在 Firebase 中启用调试视图 我想要跟踪网络流量 以便能够使用 Firebase Analytics 数据的 Charles 代理查
  • 从 LINQ to SQL 生成的 T-SQL 缺少 where 子句

    我有一个名为 CodeLookupAccessDataContext 的 DataContext 对象 它是通过 Visual Studio LINQ to SQL 类向导生成的 我扩展了该对象的功能 使其公开一些方法来返回 LINQ to
  • 如何将 javascript 代码注入到每个原型方法的开头?

    我想在 javascript 中注入代码 用于调试目的 在每个人我的 JavaScript 方法原型 这个例子只显示了一个类 但是假设我有数百个类 每个类有几十个方法 该机制应该在原型级别执行 而不需要指定每个类 方法名称 function
  • 何时“让它崩溃”以及何时捍卫 Erlang 中的代码?

    因此 带着 让它崩溃 的口号 Erlang 代码意味着能够抵御残酷的世界事件 例如意外拔出插头 硬件故障和不稳定的网络连接 另一方面 有防御性编程 https en wikipedia org wiki Defensive programm
  • Coq QArith 除以零就是零,为什么?

    我注意到在 Coq 的有理数定义中 零的倒数被定义为零 通常 除以零是没有明确定义 合法 允许的 Require Import QArith Lemma inv zero is zero 0 0 Proof unfold Qeq refle
  • 启动时不继承父文件描述符

    我需要使用 start 命令在 winXP 上启动一些进程 听起来很简单 但是有没有办法让启动的进程不会继承父进程的任何端口 我在我的程序中使用以下方法启动孩子 system start x params 现在 当父进程被杀死时 我无法再次
  • 二叉搜索树的广度优先遍历 C++

    也许是快速 简单的问题 我已经实现了一个二叉树 然后我希望将二叉搜索树转换为数组 或者至少像在数组中一样打印出来 我遇到的问题是如何获取 0 中的 NULL 标志 例如 假设我有一棵树 如下所示 10 6 12 1 8 15 4 我希望它按
  • 如何在 Cakephp 中发出 https post 请求

    我有一个要求 应用程序必须通过 HTTPS POST 进行 REST API 调用 我是 cakephp 的新手 我在想是否可以使用 httpsocket 进行 https 调用 我很感激任何帮助 Thanks 您可以使用其中任何一个 CA
  • MacPorts gcc48 无法识别命令行选项“-stdlib=libc++”

    Context 我正在尝试编译包 root numpy 它是科学分析软件 root 和python包 numpy 之间的链接 它用作根包装器 rootpy 的一部分 执行以下行时出现 g 错误 g bundle undefined dyna
  • EF AddOrUpdate 种子不更新子实体

    我在播种数据时遇到一些问题 我能够使用一个非常小的应用程序重现该问题 鉴于您有这种种子方法 protected override void Seed JunkContext context context Junks AddOrUpdate
  • GCM 响应中的multicast_id 是什么?

    示例场景 我正在使用 GCM 向多个设备发送消息 响应包含 multicast id 我该如何使用这个值 Thanks 它只是一个标识符 多播ID标识多播消息的唯一 ID 编号 该 ID 没有用处 除非您希望将其作为 Google 的 收据
  • npm运行服务报错

    我在运行命令时遇到问题 npm 运行服务 要修复它 我需要注销或重新启动我的 Ubuntu 16 04 我检查了正在运行的任务 节点没有运行 我还卸载了node和npm并再次使用NVM安装 但我仍然有问题 NPM错误日志 gt email
  • SSIS 包中的步骤如何检查时间?

    我的控制流中的起始项目需要是检查时间并设置变量的项目 控制流项中是否有一个项可以做到这一点 访问您的系统变量 System StartTime 将是包开始执行的时间 如果开始执行和需要评估当前时间的元素之间有很长的时间 您可以查看 Cont
  • SQL Server - 向所有表添加默认约束

    有没有办法编写一个脚本来检查数据库中的每个表 寻找uniqueidentifier列名为ID 然后添加一个DEFAULT的约束NEWID 到列 如果DEFAULT约束不存在 根据OP的评论澄清进行编辑 该脚本创建一个DEFAULT的约束NE
  • 解决方案范围内的预构建活动?

    我在 Visual Studio 中有一个解决方案 其中包含多个项目 我想在每次构建的一开始就运行一个命令 无论涉及哪些项目以及它们是否是最新的 本质上 我需要类似于解决方案范围内的预构建事件的东西 但不幸的是 VS 似乎不支持这些 有谁知
  • Haskell:解析命令行参数

    这更多的是一个风格问题 而不是一个如何做的问题 所以我有一个需要两个命令行参数的程序 一个字符串和一个整数 我是这样实现的 main do args aString aInteger lt getArgs let parsed n read
  • 多列代表一个值时的频率表 (R)

    我有一个这样的数据集 ID color1 color2 color3 shape1 shape2 size 55 red blue NA circle triangle small 67 yellow NA NA triangle NA m
  • 数据库连接何时以及为何昂贵?

    我正在对数据库进行一些研究 并且正在研究关系数据库的一些局限性 我发现大表的连接非常昂贵 但我不完全确定为什么 DBMS需要做什么来执行连接操作 瓶颈在哪里 非规范化如何帮助克服这种费用 其他优化技术 例如索引 有何帮助 欢迎个人经历 如果