【问题标题】:Oracle SQL VARCHAR2 datatype storageOracle SQL VARCHAR2 数据类型存储
【发布时间】:2018-02-20 08:17:19
【问题描述】:

来自 Oracle 文档:

如果您为每列指定其数据的最大长度或精度 类型,那么您的应用程序不必要地分配了许多兆字节的 内存。例如,假设查询选择 10 VARCHAR2(4000) 列和批量提取操作返回 100 行。您的 RAM 应用程序必须分配 10 x 4,000 x 100 — 几乎 4 MB。在 相反,如果列长度为 80,则您的应用程序的 RAM 必须分配 10 x 80 x 100 — 大约 78 KB。这个区别是 对单个查询很重要,您的应用程序将处理许多 并发查询。因此,您的应用程序必须分配 4 每个连接需要 MB 或 78 KB 的 RAM。

据我所知 varchar2 是可变长度数据类型,因此 DB 只会分配列实际使用的空间,即如果列在 Unicode 中只有 10 个字符,它将分配 10 个字节。但是按照上面的说法,即使column(max)只有10个字符,但是数据类型的长度定义为4000,还是会占用4000字节?

【问题讨论】:

  • 您的应用程序如何知道在 SELECT 完成之前您实际使用了 VARCHAR(4000) 的多少个字符?它不能,所以它必须分配足够的空间来接受整个VARCHAR(4000)。你读错了那段;它指的是您的应用必须分配以读取数据的空间,而不是数据库中实际使用的存储空间。
  • 是的,数据库将使用声明的长度,即使没有全部使用,该数据量也会返回到您的应用程序。
  • @TimBiegeleisen 。 . . varchar2 真的是这样吗?如果是这样,为什么要使用它而不是 char
  • 嗨戈登,也许我误读了引用的文档,也许你应该给出答案。
  • @KenWhite 我不明白我们为什么要谈论“应用程序”,而这个过程发生在数据库内部,然后才离开它的边界。我相信数据库引擎将获得结果集并通过线路将它们以块的形式发送到数据库客户端,因此它是动态分配的。对于像 Oracle DB 这样复杂的软件来说,很难发现我的列实际上不是 4000 字节,而是实际上只有 10 字节,考虑到它没有像 char 那样被空白填充。事实上,DB 知道它提取到结果中的字节数,它可以通知客户端。

标签: sql oracle


【解决方案1】:

分配的空间在磁盘上将只需要存储每一行​​的实际数据。

在内存中分配的空间将(在某些情况下)是基于数据类型所需的最大值。

【讨论】:

  • 第二个陈述只是部分正确。客户端库(OCI、JDBC)将(必须)分配能够容纳最大长度的缓冲区。但是在服务器上处理数据时(例如join、排序)Oracle不会分配最大长度
  • 同意,我的回答本质上是一般性的。更新中。
  • 那么是不是说明文档不准确?
  • 好吧,我想说的是文档中关于 Oracle 如何分配内存的单个段落永远不可能是“精确的”,因为它是一个复杂的系统 - 精确度是清晰度的敌人,因为它只是为了做个向导。
【解决方案2】:

文档本身在多个方面存在错误/误导性。引用段落之前的句子说“...长度和精度影响存储要求。”然而,就在那之后,撰写文档文章的 dufus 继续提到 RAM。磁盘上的存储装置; RAM是内存。除非我们谈论的是内存数据库(该文档文章没有),否则在说“影响存储要求”之后谈论 RAM 是没有意义的。声明的长度不会影响存储,但可能会影响内存分配。

具体来说,当应用程序(通常用Java、C#等通用语言编写)需要提前分配内存时,它可能会影响内存分配,而他们拥有的唯一信息是在数据字典中。内存可以静态分配(在编译时),但这意味着您不能使用来自实际数据的额外信息,所有字符串最多为 100 个字节;在那个阶段已知的所有内容最多为 4000 字节。内存也可以动态分配,并且可以使用额外的信息 - 但它要慢得多,慢得多!

在数据库和用其他语言编写的应用程序之间的许多“交互”中,您甚至没有动态内存分配的选项;在当今世界,假设“时间”比 RAM 更有价值,因此如果您发现代码内存不足,请购买更多 RAM 而不必担心动态内存分配。这意味着,如果您声明 VARCHAR2(4000),您应该预期会以一种浪费的方式分配大量 RAM。只需声明 VARCHAR2(100) 即可。

【讨论】:

  • 感谢您的回答,但正如您所建议的,我不了解基于数据字典信息的内存分配。数据字典提供关于列维度的信息,关于由多行组成的结果集的信息。应用程序如何以及为什么要提前(静态)分配内存?
  • @joe.d “数据字典”是数据库为其自身目的维护的“内部”(系统)表的集合。因此,例如,当您创建表时,会将有关表名、列名及其顺序以及每列的数据类型(包括长度、精度等)的信息添加到数据字典中。这是在任何行之前完成的被插入到表中!数据字典中唯一可用的信息是 VARCHAR2 列的 DECLARED(不是实际!)长度。
  • @joe.d 当一个应用程序(例如,用 Java 编写的)创建一个记录数组时,每个元素(记录)由员工编号、雇用日期、工资等(或任何表列是),内存必须提前分配。用于此目的的唯一信息是数据字典中的任何信息。在从数据库中读取数据之前,编译器不知道表中字符串的实际最大长度 - 这是在编译之后。
  • 对不起,我不同意。如果我将数据库行映射到对象类型,我不必为此预先分配任何内存空间。如果我检索多行,我也不会在使用 Java 集合时预先分配内存。我的应用程序查询数据库并获取将在块中返回的任何数据库。您描述的方式没有预分配机制,即基于数据字典信息。这没有任何意义,因为列定义(在数据字典中)和结果集大小之间再次没有直接关联(还有其他因素)。对我来说没有意义。也许你可以澄清一下。
【解决方案3】:

这个有趣问题的来源是here

文章对VARCHAR2存储很清楚:

Oracle 数据库空白填充值存储在 CHAR 列中,但不是 存储在 VARCHAR2 列中的值。因此,VARCHAR2 列使用 空间比 CHAR 列更有效。

他们对 RAM 分配的看法是,如果您没有为 VARCHAR2 列定义限制,您的应用程序将不知道要分配多少 RAM。此外,如果限制太高,一开始会分配太多 RAM,因此请始终选择最有效的限制。

还有一篇关于数据类型here的OCI使用的综合文章。

【讨论】:

  • 应用程序从 DB 获取数据,无论 DB 通过网络发送什么。所以 DB 会发送非空格填充的列,对吗?
  • 是的,这与 DB (SGA) 中的 RAM 使用量无关,甚至与客户端从 DB (PGA/UGA) 收到的内容无关。他们谈论的是在应用服务器上预分配 RAM,或应用内 RAM。我假设它们是,因为这篇文章被称为“数据库应用程序中的数据类型”。
  • 是什么让您认为应用服务器必须预先分配 RAM?
  • 应用服务器上的应用...不是服务器本身
猜你喜欢
  • 2019-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-28
  • 1970-01-01
  • 2021-05-18
  • 2011-12-06
  • 1970-01-01
相关资源
最近更新 更多