通过添加索引列优化 SQL 数据库

Posted

技术标签:

【中文标题】通过添加索引列优化 SQL 数据库【英文标题】:Optimize SQL databases by adding index columns 【发布时间】:2010-05-26 11:47:56 【问题描述】:

假设我有一个看起来像这样的数据库;

Product with columns [ProductName] [Price] [Misc] [Etc]
Order with columns [OrderID] [ProductName] [Quantity] [Misc] [Etc] 

ProductName 是 Product 的主键,具有某种字符串类型,并且是唯一的。OrderID 是某种整数类型的主键,而 ProductName 是一个外键。

假设我将 Product 的主键更改为整数类型的新列,即[ProductID]

这会减少数据库大小并优化连接这两个表的查找(以及类似的操作),还是这些优化由 (most/general/main) SQL 数据库实现自动执行?

从技术上讲,使用(字符串)ProductName 作为Product 中的主键,数据库应该能够将Order 中的ProductName 列简单地实现为指向Product 中一行的指针,并执行JOIN就像使用整数作为外键一样快速,这是实现 SQL 的标准方式吗?

更新: 这个问题是关于 SQL 服务器如何处理外键,而不是产品表是否需要序列号,或者我如何处理数据库中的产品名称更改。

【问题讨论】:

【参考方案1】:

字符串主键是个坏主意,因此将其更改为 INT 将有助于提高性能。大多数数据库使用主键索引进行查找和比较,如果可能,请选择一个简短的主键——一列。您将主键列用于连接(根据连接列中的公共值组合来自两个或多个表的数据)、查询检索以及对查询结果集进行分组或排序。索引条目越简短,数据库执行查找和比较的速度就越快。

更不用说,如果产品名称发生变化,您将如何处理?更新包含产品名称作为外键的所有行?

我说得再好不过了,所以看看这个答案:Should I design a table with a primary key of varchar or int,引用那个答案:

使用 VARCHAR(10) 或 (20) 只是使用 占用太多空间 - 10 或 20 个字节 而不是 4,还有很多人 不知道 - 聚类键值 将在每个索引上重复 每个非集群的条目 表上的索引,所以有可能, 你浪费了很多空间(不是 只是在磁盘上 - 这很便宜 - 但也 在 SQL Server 的主内存中)。还, 因为它是可变的(可能是 4,可能 是 20 个字符)SQL 服务器更难 正确维护一个良好的索引 结构

【讨论】:

+1 指出更改产品名称的问题【参考方案2】:

整数列在连接中比字符串表现更好

整数 autoinc 列作为主聚集键有利于插入

【讨论】:

【参考方案3】:

我不会减少数据库大小(大概您会保留产品名称字段),但肯定会提高查​​找性能。

【讨论】:

【参考方案4】:

在大多数实现中,整数数据类型的大小将小于字符串(CHARVARCHAR 等),这将使您的索引更小。

另外,比较字符串还有一些问题:

    某些数据库,即mysql,会压缩字符串键,这会降低搜索效率。

    使用自然语言标识符的字符串B-Trees 的并发平衡性往往低于整数B-Trees。由于自然语言单词在整个字母表中分布不均,更多的更新和插入将进入同一个块,从而增加页面拆分的数量并最终增加索引大小。为了解决这个问题,Oracle 在索引中支持REVERSE 子句。

    比较两个字符串时,应考虑排序规则。通常,这并不重要,但是,它确实会增加一些开销。

【讨论】:

B、B+ 和 B-* 树是总是平衡的。 REVERSE 不会影响 B 树存储数据的方式,它只是反转索引中字符串的顺序,以便您可以在字符串的开头进行 LIKE 搜索。在 SQL Server 中,您可以通过在反转字符串上添加索引计算列来实现此目的。并且 CHAR 列不会大于整数,只要您使用的字符少于 4 个即可。 @Dave:这里的“平衡”不是“高度平衡”而是“并发平衡”,即。 e.页面争用减少。 Oracle 不会对带有前导 %LIKE 谓词使用 REVERSE 索引,它只能在等值连接上使用这样的索引。【参考方案5】:

主键应该是唯一的,在创建行时存在并且尽可能不可变。 IMO,关于是否使用代理密钥的讨论应该次要于数据完整性问题。

例如,如果产品上印有序列号,该序列号在输入数据库中的行时必须存在,并且保证是唯一的,那么 IMO 将使一个好的主键。原因是此值将用作其他表中的外键,它可以节省您额外查找以获取产品序列号的费用。在您进入数百万行之前,额外的存储空间是无关紧要的。但是,如果序列号是由其他制造商盖章的,因此您无法保证唯一性(“它可能是唯一的”还不够好),那么代理是合适的。事实上,如果不是大多数“产品”表使用代理键,我什至会说很大一部分,因为没有保证在进入时可用的值,保证是唯一的并且相对不可变的可用作为一把钥匙。

然而,许多使用代理键的开发人员忽略了每个具有代理键的表应该有另一个键(即唯一约束)。因此,在您使用产品的情况下,即使您添加整数主键,您仍然应该对产品名称具有唯一约束。产品名称的唯一性约束创建了所谓的候选键,其中整数值是主键。

代理键是在幕后使用的。虽然整数键性能最好并且易于创建,但它们有一个缺点:应用程序开发人员向用户显示键值很容易,甚至很诱人。这是国际海事组织的错误。用户不应该看到键值,否则他们将依赖值本身,如果您需要对值重新排序(例如使用数据库合并)或者如果您使用在由身份值,它们依赖于顺序的值。只要你从不向用户展示价值,使用整数 PK 就可以了。

【讨论】:

以上是关于通过添加索引列优化 SQL 数据库的主要内容,如果未能解决你的问题,请参考以下文章

索引优化驱动SQL优化总结

索引视图SQL优化以及数据库存储过程

SQL Server 2016:内存列存储索引

SQL Server 索引优化 ——索引缺失

160531SQL优化-索引

oracle sql优化技巧