选择主键类型

时间:2009-08-26 21:16:05

标签: sql-server primary-key scalability

我有一个表,每秒可能会有大量的插入,我正在尝试选择一种我想要使用的主键。为了说明的目的,让我们说,它是用户表。我试图在使用GUID和BIGINT作为主键并最终作为整个应用程序的UserID之间进行选择。如果我使用GUID,我会保存到数据库的行程以生成新的ID,但GUID不是“用户友好的”,并且不可能通过此ID(我打算这样做)对表进行分区。使用BIGINT更方便,但生成它是一个问题 - 我不能使用IDENTITY(这是有原因的),所以我唯一的选择是有一些包含最后使用的ID的帮助表然后我调用它存储过程:

create proc GetNewID @ID BIGINT OUTPUT
as
begin
update HelperIDTable set @ID=id, id = id + 1 
end

获取新ID。但是这个助手表是一个明显的瓶颈,我关心它每秒可以做多少次更新。

我非常喜欢使用BIGINT作为pk的想法,但瓶颈问题让我感到担忧 - 有没有办法粗略估计每秒可以生成多少个id?我意识到它在很大程度上取决于硬件,但是有任何物理限制以及我们在多大程度上看待它们? 100的/秒? 1000的/秒?

有关如何解决问题的任何想法都非常感谢!这个问题不让我睡了好多晚了!

谢谢! 安德烈

5 个答案:

答案 0 :(得分:2)

GUID似乎是一个很自然的选择 - 如果你真的必须这样做,你可能会争辩将它用于表的PRIMARY KEY - 唯一标识数据库中行的单个值。

我强烈建议不要使用GUID列作为群集密钥,默认情况下SQL Server会执行此操作,除非您明确告知不要这样做。

作为Kimberly Tripp - 索引女王 - 以及其他人已多次声明 - GUID作为聚类键不是最佳的,因为由于其随机性,它将导致大量页面和索引碎片并且通常表现不佳。

是的,我知道 - 在SQL Server 2005及更高版本中有newsequentialid() - 但即使这样也不是真正完全顺序的,因此也会遇到与GUID相同的问题 - 只是不那么显着。< / p>

然后还有另一个需要考虑的问题:表格上的聚类键也会被添加到表格中每个非聚集索引的每个条目上 - 因此你真的想确保它尽可能小。通常,对于绝大多数表来说,具有2亿行的INT应该足够 - 并且与作为群集密钥的GUID相比,您可以在磁盘和服务器内存中节省数百兆的存储空间。

总而言之:除非你有充分的理由,否则我总是建议将INT IDENTITY字段作为您桌面上的主要/群集密钥。

马克

答案 1 :(得分:1)

我尝试对除小查找表之外的所有表使用GUID PK。 GUID概念确保可以安全地在memeory中创建对象的标识,而无需往返数据库并在以后保存而不更改标识。

当您需要“人类可读”ID时,您可以在保存时使用自动增量int。对于分区,您也可以稍后通过数据库计划为一个镜头中的许多用户创建BIGINT。

答案 2 :(得分:1)

出于商业原因,您是否需要主键或存储密钥? 有关PK与群集密钥主题的更详细的帖子,请参阅stackoverflow.com/questions/1151625/int-vs-unique-identifier-for-id-field-in-database

你真的要详细说明为什么你不能使用IDENTITY。手动生成ID,特别是在服务器上使用额外的rountrip和更新只是为了生成插入的每个ID,它将无法扩展。你很幸运能达到每秒100秒以下的速度。问题不仅在于rountrip和更新时间,而且主要来自ID生成更新与插入批处理的交互:插入批处理事务将序列化ID生成。 woraround是在单独的会话中分离ID生成,因此它可以自动提交,但是插入批处理是没有意义的,因为ID genartion没有被批处理:它等待每个ID生成后的日志刷新为了提交。与此相比,uuid将在您的手动ID生成周围运行。但由于分裂,uuid对于关键密钥是可怕的选择。

答案 3 :(得分:0)

尝试使用脚本命中数据库,也许使用jmeter来模拟并发命中。也许你可以自己测量一下你能承受多少负荷。你的DB也可能造成瓶颈。哪一个?我希望PostgreSQL能够承受重载,就像雅虎和Skype一样

答案 4 :(得分:0)

需要认真测试的想法:尝试批量创建(插入)新行 - 例如1000(10,000?1M?)。你可以有一个主(也就是瓶颈)表,列出下一个要使用的表,或者你可能有一个类似

的查询
 select min(id) where (name = '')

在早上,每小时或每当你使用一定数量的免费行时,生成一批新的emtpy行。这只解决了生成新ID的问题,但如果这是它可能有用的主要瓶颈。

表分区选项:假设有一个bigint ID列,您如何定义分区?如果您允许每天1G行,您可以在晚上设置新分区(第1天= 1,000,000,000到1,999,999,999,第2天= 2,000,000,000到2,999,999,999等),然后在准备就绪时将其交换。您当然限制为1000个分区,因此使用bigints,在用完ID之前,您将耗尽分区。