通过为每列设置预定义的数据类型,关系数据库能获得什么?


44

我现在正在使用SQL数据库,这一直使我感到好奇,但是Google搜索的机会并不多:为什么使用严格的数据类型?

我了解为什么会有几种不同的数据类型,例如区分二进制数据和纯文本数据很重要。现在,我知道将二进制数据存储为自己的格式比将二进制数据的1和0格式存储为纯文本要好得多。

但是我明白的是拥有这么多种不同的数据类型的好处是什么:

  • 为什么mediumtextlongtexttext
  • 为什么decimalfloatint
  • 等等

告诉数据库“此列的条目中只有256个字节的纯文本数据”有什么好处。或“此列最多可以包含16,777,215字节的文本条目”?

这是性能优势吗?如果是这样,为什么在事前知道条目的大小对性能有何帮助?或更确切地说是其他东西吗?


2
我以为这个问题应该已经在这里了,但是我搜索了该网站,却没有发现任何有用的信息。
约翰·多伊


6
如果您没有不同的decimalfloatint类型,您将期望1 / 3做什么?那1.0 / 3.0呢 你能相信,当你把columnA通过columnB,你会得到你所期望的结果?
安德鲁·皮利斯

2
@johndoe我认为没有必要,但这可能非常方便。假设您要强制执行一个约束,即商店的库存不能低于其每月预期销售额的5%。或者您想确保每个部门的总预算不超过总预算的20%。它也可能出现在您要在使用相同数据库的多个应用程序中以相同方式进行计算的计算列中。
安德鲁·皮利斯

2
值得注意的是,SQLite 不会 为每个列设置预定义的类型:“ SQLite是“无类型的”。这意味着您可以在任何表的任何列中存储所需的任何类型的数据,而不管该列的声明数据类型如何。 “
总理

Answers:


50

SQL是一种静态类型的语言。这意味着您必须先知道变量(在这种情况下为字段)的类型,然后才能使用它。这与动态类型的语言相反,事实并非一定如此。

SQL的核心旨在在关系数据库引擎中定义数据(DDL)和访问数据(DML)。对于这种类型的系统,静态类型比动态类型具有多个优点。

  • 固定大小后,用于快速访问特定记录的索引可以很好地工作。考虑一个使用索引的查询,该索引可能具有多个字段:如果提前知道数据类型和大小,则可以非常快速地将谓词(WHERE子句或JOIN条件)与索引中的值进行比较,并更快地找到所需的记录。

  • 考虑两个数值。在动态类型系统中,它们的大小可能是可变的(请考虑Java BigInteger或Python内置的任意精度整数)。如果要比较整数,则需要首先知道它们的位长。这是整数比较的一个方面,现代语言在很大程度上掩盖了这一点,但是在CPU级别上却是非常真实的。如果尺寸是固定的,并且提前知道,则从该过程中删除整个步骤。同样,数据库应该能够尽快处理成千上万的交易。速度为王。

  • SQL是在1970年代设计的。在微计算的早期,内存非常宝贵。限制数据有助于控制存储需求。如果整数从不超过一个字节,为什么要为其分配更多的存储空间?在有限的内存时代,这是浪费空间。即使在现代,那些多余的字节也会加起来并破坏CPU缓存的性能。请记住,这些是数据库引擎,每秒可能处理数百个事务,而不仅仅是您的小型开发环境。

  • 按照有限的存储方式,将单个记录放入内存中的单个页面将很有帮助。翻过一页后,会有更多的页面遗漏和更慢的内存访问。较新的引擎已进行了优化,以减少此问题,但仍然存在。通过适当调整数据大小,可以减轻这种风险。

  • 此外,在现代,SQL用于通过ORMODBC或某些其他层来插入其他语言。这些语言中的一些具有关于要求强静态类型的规则。最好符合更严格的要求,因为动态类型化的语言可以比其他方式更轻松地处理静态类型。

  • SQL支持静态类型,因为数据库引擎需要它来提高性能,如上所示。

有趣的是,注意到有些SQL的实现不是强类型的。SQLite可能是这种关系数据库引擎最流行的示例。再说一次,它是为在单个系统上单线程使用而设计的,因此对性能的关注可能不会像在企业Oracle数据库中每分钟处理数百万个请求那样明显。


SQLite的数据类型可以区分数字数据和文本数据,但只有5个“类”的数据存储:sqlite.org/datatype3.html
FrustratedWithFormsDesigner

1
我知道@FrustratedWithFormsDesigner,但是它仍然远没有像SQL Server,Oracle或PostgreSQL这样的引擎严格。

SQL不仅是静态类型的-由于存在检查约束,它还有效地支持优化类型。
Gardenhead '17

4
尽管在第一个项目符号中暗示,但Indexes更基本地说:拥有数据类型使数据库引擎能够理解数据,进行比较(更大/更小的数字,更早/更晚的日期时间,字母的前/后),因此可以进行排序和查询
罗勒·布尔克

因此,如果大小很重要...并且sql需要事先知道...“ Zillion”事务的确切大小是多少?
WernerCD '17

24

第一:纯文本是二进制的(甚至不是UTF8或ASCII字符“ 0”和“ 1”,而是实际的开/关位)

也就是说,某些原因是:

  • 业务/设计约束:在PERSON表的HEIGHT列中允许输入7626355112是错误的。在INVOICE的DATE列中允许“ Howya”将是错误的。
  • 错误代码更少:您不必编写代码来确保从日期列检索的数据确实是日期。如果列类型是动态的,则在读取它们时必须进行很多类型检查。
  • 计算效率:如果列的类型为INTEGER,而您对其进行SUM(),则RDBMS不必应用浮点算法。
  • 存储效率:指出列为VARCHAR(10),则RDBMS可以更精确地分配空间。
  • 参照完整性和唯一性:表的PK(或FK)不应允许使用浮点数,因为浮点数相等是棘手的,因此必须以非浮点类型声明它们,例如字符或整数。
  • 存在带有动态(非严格)列类型(SQLite)的RDBMS。它使用“类型相似性”的概念,同时仍然允许您将几乎所有内容插入任何列而无需抱怨。这里有一些权衡,这里将不讨论。看到这个问题

8

这样一来,写入数据库的基础代码就可以分配并使用固定大小的记录,如果它知道特定字段可以包含0到256个字符的文本,那么它可以分配一个256字节的块来存储它。

这可以使事情变得更快,例如,您不必为用户类型分配额外的存储空间,因为给定的字段始终在记录中开始x字节,而对该字段的搜索或选择知道总是在每个记录中检查x字节,依此类推。


如果所有的答案都可以这么简洁明了地讲……
Darren Ringer

6

当为数据库的列提供定义的类型时,通常将类型本身定义为具有一定大小的位。结果是:

1)当数据库引擎遍历表中的行时,它无需执行任何花哨的解析即可确定每条记录的结束位置,它只需知道每行包含32个字节即可,因此下一条记录足以将32个字节添加到当前记录位置。

2)在一行中查找某个字段时,可以再次知道该字段的确切偏移量而无需解析任何内容,因此列查找是一种简单的算术运算,而不是可能耗费大量数据的处理。


固定长度的字段可以使记录长度和字段偏移保持一致,从而使处理效率更高,但是可变长度的字段可以使这些好处无效,因为字段的记录长度和偏移可以变化。同样,记录级压缩将导致记录变长,因此不能简单地计算给定记录的位置。
Zenilogix

的确如此,很长一段时间以来,通常都建议避免使用可变长度字段。我不知道大型公司是如何做到的,但是您似乎可以通过使引擎将宽度可变的字段存储在用户不可见的表或内存块中,并使引擎恢复固定长度的一些好处。这些字段的主表表示形式是其中的(固定宽度)“指针”。考虑到您应该首先定期对可变长度字段进行完整扫描,因此间接性能的提高可能值得保持固定宽度。
UserNotFound

3

您问为什么 DBMS具有静态数据类型。

  1. 查找速度。DBMS的全部要点是存储的数据要远远多于您可能加载到程序中的数据。想一想“过去十年中世界上所有产生的信用卡单据”。为了有效地搜索此类数据,固定长度的数据类型很有用。对于日期戳和帐号等结构化数据尤其如此。如果您提前知道要处理的内容,则可以更轻松地加载到高效索引中。

  2. 诚信与约束。如果数据具有固定的数据类型,则更容易保持数据干净。

  3. 历史。当计算机只有几兆字节的RAM时,RDBMS便开始了,而TB级的存储则非常昂贵。在这种情况下,在表的每一行中保存十几个字节可以节省数千美元和数小时的时间。

  4. 客户群的诅咒。当今的RDBMS是非常复杂,高度优化的软件包,并且已经使用了数十年以累积数据。他们很成熟。他们工作。如今,导致大规模数据丢失的RDBMS崩溃非常罕见。对于大多数组织来说,切换到具有更灵活的数据键入系统的东西不值得付出成本或承担风险。

打个比方:在一个较窄的轨距上,城市地铁系统可能会工作得更好(更安静,更快,更节能),这可能是盲目的。但是,您如何改变纽约地铁系统中的所有轨道以实现这些改进?事实并非如此,因此您可以优化自己拥有的东西。


3

通常,您越详细地告知数据库要存储的内容,它就越会尝试优化与该数据相关的各种性能指标,例如在磁盘上分配多少空间或在检索数据时分配多少内存。 。

为什么选择中文字,长文字和文字?

不知道您使用的哪个数据库,所以我不得不猜测:我猜这些数据类型中有两个具有上限,而其中一个没有。使用具有上限的文本的数据类型可以告诉数据库每条记录将需要多少存储空间。某些数据库也可能以不同的方式存储大(可能是无限制的)文本和小的定长文本(这可能因数据库而异,请查阅您的手册以了解您的信息)。

为什么选择十进制,浮点和整数?

不同级别的精度需要不同的存储量,并非每次使用都需要最高的精度。例如,请参见此处:https : //docs.oracle.com/cd/B28359_01/server.111/b28286/sql_elements001.htm#SQLRF50950

Oracle具有许多不同的数字类型,它们在表示精度的级别和数量的大小方面具有不同的存储要求和不同的功能。


2

在某种程度上,这是历史。

从前,表格数据存储在由固定长度记录组成的文件中,而固定长度记录又由预定义字段构成,这样,给定字段在每个记录中始终具有相同的类型和位置。这使得处理高效并且限制了编码的复杂性。

在这样的文件中添加一些索引,您就可以建立一个关系数据库。

随着关系数据库的发展,他们开始引入更多的数据类型和存储选项,包括可变长度文本或二进制字段。但是,这引入了可变长度记录,并打破了通过计算一致地定位记录或通过固定偏移量来连续定位记录的能力。没关系,今天的机器比以前强大得多。

有时,为字段设置特定大小以帮助实施一些业务逻辑很有用-例如,北美电话号码为10位数字。在大多数情况下,这只是计算方面的遗留问题。


1

如果数据库使用固定大小的记录,则即使更改了其内容,该数据库中的任何记录也将继续容纳在同一位置。相反,如果数据库尝试使用字段所需的确切存储量来存储记录,则将Emma Smith的名字更改为Emma Johnson可能会导致她的记录太大而无法容纳其当前位置。如果将记录移到有足够空间的某个位置,则任何需要跟踪记录位置的索引都需要更新以反映新位置。

有多种方法可以减少与此类更新相关的成本。例如,如果系统维护记录编号和数据位置的列表,则该列表将是记录移动时唯一需要更新的内容。不幸的是,这样的方法仍然具有巨大的成本(例如,保持记录号和位置之间的映射将要求记录检索将需要额外的步骤来检索与给定记录号相关联的数据)。使用固定大小的记录看似效率低下,但它使事情变得简单得多。


1

对于您作为Web开发人员所做的很多事情,都不需要了解“幕后”发生的事情。但是,有时候它会有所帮助。

告诉数据库“此列的条目中只有256个字节的纯文本数据”有什么好处。或“此列最多可以包含16,777,215字节的文本条目”?

您怀疑,原因在于效率。抽象泄漏SELECT author FROM books当知道表中所有字段的大小时,类似这样的查询可以很快运行。

正如乔尔所说,

关系数据库如何实现SELECT author FROM books?在关系数据库中,表(例如,books表)中的每一行的长度完全相同,以字节为单位,并且每个字段始终与行的开头保持固定的偏移量。因此,例如,如果books表中的每个记录长为100个字节,并且author字段位于偏移量23处,那么将有作者存储在字节23、123、223、323等处。要移到的代码是什么?查询结果中的下一条记录?基本上是这样的:

pointer += 100;

一条CPU指令。Faaaaaaaaaast。

很多时候,您的工作与足够细致的基础相距甚远,因此您无需关心它。作为基于PHP的Web开发人员,您是否关心代码使用多少CPU指令?大多数时候,不,不是真的。但有时出于以下两个原因,很有用:它可以解释您的库所做的决定;有时您确实需要关心自己的代码的速度。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.