sql - 主键选择的性能

标签 sql sql-server-2008

我们有一个包含 CreateDateTime PK 的表。执行插入的程序是多线程的。显然,这不是线程安全的。有一个 3 列复合键,可以从表中的现有数据中生成。这是一个日志表,预计流量会很高。性能是主要关注点。

我们的一位开发人员认为,由于 SQL 在内部存储日期时间(纪元?)的方式,DateTime 是出于性能原因的最佳 PK。

我建议我们用 3 列创建一个组合键。此 key 更改是否会对性能产生负面影响?

也有人建议我们使用 GUID PK。性能再次受到质疑。

最好切换到复合键吗?如果是,我们如何解决/解释这些性能问题?

最佳答案

GUID 似乎是您的主键的自然选择 - 如果您真的必须,您可能会争辩说将它用于表的 PRIMARY KEY。我强烈建议不要做的是使用 GUID 列作为集群键,SQL Server 默认情况下会这样做,除非您明确告诉它不要这样做。

您确实需要将两个问题分开:

1) primary key 是一种逻辑结构 - 唯一且可靠地标识表中每一行的候选键之一。这可以是任何东西,实际上 - 一个 INT、一个 GUID、一个字符串 - 选择对您的场景最有意义的东西。

2) 聚类键(在表中定义“聚簇索引”的一列或多列)- 这是一个物理存储相关的东西,在这里, 一个小的、稳定的、不断增加的数据类型是你最好的选择——INT 或 BIGINT 作为你的默认选项。

默认情况下,SQL Server 表上的主键也用作聚类键 - 但这并不需要那样做!当将以前基于 GUID 的主键/聚簇键分解为两个单独的键时,我个人看到了巨大的性能提升 - GUID 上的主(逻辑)键和单独的 INT IDENTITY(1, 1)专栏。

作为Kimberly Tripp - 索引女王 - 其他人已经多次声明 - 作为集群键的 GUID 不是最佳选择,因为由于其随机性,它将导致大量页面和索引碎片以及通常较差的性能。

是的,我知道 - SQL Server 2005 及更高版本中有 newsequentialid() - 但即使那样也不是真正和完全顺序的,因此也遇到与 GUID 相同的问题 - 只是一点点不太明显。

然后还有另一个问题需要考虑:表上的聚簇键也将添加到表上每个非聚簇索引的每个条目中 - 因此您确实希望确保它尽可能小.通常,具有 2+ 十亿行的 INT 应该足以满足绝大多数表的需求 - 与作为集群键的 GUID 相比,您可以在磁盘和服务器内存中节省数百兆字节的存储空间。

快速计算 - 使用 INT 与 GUID 作为主键和集群键:

  • 包含 1'000'000 行的基表(3.8 MB 与 15.26 MB)
  • 6 个非聚集索引(22.89 MB 与 91.55 MB)

总计:25 MB 与 106 MB - 而且这只是在一张表上!

还有一些值得思考的东西 - 金伯利·特里普 (Kimberly Tripp) 的优秀作品 - 读一遍,再读一遍,消化它!这真的是 SQL Server 索引福音。

至于复合键:在我看来,主要的缺点是所有想要引用这个复合主键的表现在都必须有一个复合主键,所有 复合主键中定义的列.当您有很多查询需要将子表连接到具有此复合键的表时,这会变得非常笨拙。

DATEITME 单独作为主键似乎不是一个好主意 - 在 SQL Server 中,DATETIME 的精度为 3.33 毫秒,因此很有可能在繁忙的系统中,您将拥有非唯一值 - 这对于 PK 来说不是一个好主意!

如果性能是您的首要任务,那么我绝对会推荐将单个 INT IDENTITY 列(即使它是代理列)用于您唯一的聚集主键索引。

关于sql - 主键选择的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9926135/

相关文章:

java - 将 Oracle 日期算术转换为在 HSQLDB 中工作

mysql - SELECT INNER JOIN 只返回一个结果

sql-server-2008 - SQL Server : The total size of an index or primary key cannot exceed 900 bytes

mysql - 如何处理Mysql中分层数据的数据库?

sql - 在 InnoDB/MySQL 中使用外键约束和级联

sql - 使用多个 WITH tablename AS (...) 语句 SQL Server

sql - 带有检查约束的自定义函数 SQL Server 2008

sql - 检查sql server中文件是否存在?

sql - 以月 DD,YYYY 格式显示日期

sql - 插入表中.. 链接服务器上的 exec 不起作用