none
到底该怎么设置一个不会重复的数字主键才是对的? RRS feed

  • 问题

  • 说一下我目前的做法,主键列名为ID,设置类型为int,自增,初始值1,自增值1.这样做有个很麻烦的问题。比如我有8条数据,id最大为8,我删掉了第3条,然后insert一条进去,我希望它能填充这个删除的第3条,结果他添加的id是9,如果以后我数据较多的话,int迟早要超出最大范围而溢出。怎么解决这个问题,用什么做法才是合适的?
    2012年11月10日 12:44

答案

  • 找到那两篇帖子了

    http://www.cnblogs.com/ATree/archive/2011/05/04/SQL-SERVER-GUID-INT.html

    http://bbs.csdn.net/topics/310173380

    两篇帖子都讨论了使用GUID还是使用int自增列,LZ你说到使用那种方法是合适的,这个要看你的业务,如果你的表不需要经常删除数据的话使用int自增列就可以了

    如果经常删除的话或者需要数据库迁移,例如mssql迁移到mysql使用guid

    以上属于个人意见


    给我写信: QQ我:点击这里给我发消息

    2012年11月10日 13:42
  • 除了INT,SQL server 还支持 bigint 跟 uniqueidentifier,

    而bigint可以精确的表示从-2^63到2^63-1(即从-9,223,372,036,854,775,808到 9,223,372,036,854,775,807)之间的整数。

    uniqueidentifier 也应该是取之不尽的。

    2012年11月10日 13:45
  • Better to avoid guid as clustered pkey, too many page splits. 
    2012年11月10日 20:41
  • 一般用 int , 结合表(非常久的数据可以放到历史表,把 id 值合出来重新使用),如果数据量确实比较大,可以考虑  bigint

    guid 长度太大了一点,所以一般比较少考虑用这个

    如果存在大量数据删除,考虑在删除后,使用 dbcc checkident 重置一下自增值,少量数据删除导致的浪费一般不考虑

    业务上避免使用 delete+insert 来代替 update

    2012年11月12日 3:56

全部回复

  • LZ您好

    int迟早要超出最大范围而溢出

    int:从-2^31(-2,147,483,648)到2^31-1(2,147,483,647)的整型数据,存储大小为 4 个字节。int类型,最大可以存储32位的数据

    有二十多亿

    记得以前在csdn论坛也有人讨论过这个问题,当数据量达到这麽大的时候LZ要考虑分表,分库,归档历史数据了


    给我写信: QQ我:点击这里给我发消息

    2012年11月10日 13:13
  • 找到那两篇帖子了

    http://www.cnblogs.com/ATree/archive/2011/05/04/SQL-SERVER-GUID-INT.html

    http://bbs.csdn.net/topics/310173380

    两篇帖子都讨论了使用GUID还是使用int自增列,LZ你说到使用那种方法是合适的,这个要看你的业务,如果你的表不需要经常删除数据的话使用int自增列就可以了

    如果经常删除的话或者需要数据库迁移,例如mssql迁移到mysql使用guid

    以上属于个人意见


    给我写信: QQ我:点击这里给我发消息

    2012年11月10日 13:42
  • 除了INT,SQL server 还支持 bigint 跟 uniqueidentifier,

    而bigint可以精确的表示从-2^63到2^63-1(即从-9,223,372,036,854,775,808到 9,223,372,036,854,775,807)之间的整数。

    uniqueidentifier 也应该是取之不尽的。

    2012年11月10日 13:45
  • bigint也是可以的

    给我写信: QQ我:点击这里给我发消息

    2012年11月10日 13:59
  • Better to avoid guid as clustered pkey, too many page splits. 
    2012年11月10日 20:41
  • Better to avoid guid as clustered pkey, too many page splits. 

    NEWSEQUENTIALID

    想不想时已是想,不如不想都不想。

    2012年11月11日 0:31
    版主
  • 最好不要把identity或者GUID作为 clustered pkey ,

    而尽量选择一个狭小的,静态的,递增的对业务有意义的键作为clustered pkey,这样既可以避免碎片,又利于范围查询。


    Please click the Mark as Answer button if a post solves your problem!



    2012年11月11日 4:52
  • int 不够用的话,可以用bigint。
    2012年11月11日 14:27
    版主
  • Better to avoid guid as clustered pkey, too many page splits. 

    NEWSEQUENTIALID

    想不想时已是想,不如不想都不想。

    It's not guaranteed because OS will start a new guid evert time reboot, that new guid doesn't follow previous sequence.
    2012年11月11日 19:32
  • rmiao大侠说得没错

    给我写信: QQ我:点击这里给我发消息

    2012年11月12日 3:46
  • 一般用 int , 结合表(非常久的数据可以放到历史表,把 id 值合出来重新使用),如果数据量确实比较大,可以考虑  bigint

    guid 长度太大了一点,所以一般比较少考虑用这个

    如果存在大量数据删除,考虑在删除后,使用 dbcc checkident 重置一下自增值,少量数据删除导致的浪费一般不考虑

    业务上避免使用 delete+insert 来代替 update

    2012年11月12日 3:56
  • Better to avoid guid as clustered pkey, too many page splits. 

    NEWSEQUENTIALID

    想不想时已是想,不如不想都不想。

    It's not guaranteed because OS will start a new guid evert time reboot, that new guid doesn't follow previous sequence.

    没关系啊,不需要完全顺序的。这是B+ Tree,不是数组。

    想不想时已是想,不如不想都不想。

    2012年11月12日 6:00
    版主
  • 一般用 int , 结合表(非常久的数据可以放到历史表,把 id 值合出来重新使用),如果数据量确实比较大,可以考虑  bigint

    guid 长度太大了一点,所以一般比较少考虑用这个

    如果存在大量数据删除,考虑在删除后,使用 dbcc checkident 重置一下自增值,少量数据删除导致的浪费一般不考虑

    业务上避免使用 delete+insert 来代替 update


    guid的好处是,可以在多个系统中(不限于数据库)保持唯一性。同一个数据库一般不需要用guid。

    想不想时已是想,不如不想都不想。

    2012年11月12日 6:02
    版主
  • Better to avoid guid as clustered pkey, too many page splits. 

    NEWSEQUENTIALID

    想不想时已是想,不如不想都不想。

    It's not guaranteed because OS will start a new guid evert time reboot, that new guid doesn't follow previous sequence.

    没关系啊,不需要完全顺序的。这是B+ Tree,不是数组。

    想不想时已是想,不如不想都不想。

    Will cause table split if use it as clustered pkey, big performance issue.
    2012年11月12日 14:35
  • Will cause table split if use it as clustered pkey, big performance issue.
    只有重启的时候guid才不是顺序的,所以只有那个时候才作page split,对性能没有什么影响。

    想不想时已是想,不如不想都不想。

    2012年11月12日 15:07
    版主
  • All new rows will follow current sequence, means keep spliting if that sequence is not at the end of the table..
    2012年11月12日 16:04
  • guid(newid())作为聚集索引会产生rmio说的分页问题,而且因为字段太长对于存储也是问题(lookup key 对于其他Index)

    使用IDENTITY应该不会产生分页但是也会有GAP的问题(比如ROLLBACK等等),而且如果操作频繁的话可能会产生hot spots 。

    所以如果你想要连续的还是自己写逻辑,数据类型可以使用BIGINT个人感觉应该够用了。

    bigint

    -2^63 (-9,223,372,036,854,775,808) to 2^63-1 (9,223,372,036,854,775,807)

    NEWSEQUENTIALID() 安装微软的讲法应该不会出现PAGE SPLIT的问题,因为是递增的。

    Creates a GUID that is greater than any GUID previously generated by this function on a specified computer since Windows was started.


    2012年11月13日 1:08
  • 如果说用NEWSEQUENTIALID() ,能够确保每次机器重启后产生的GUID跟之前产生的GUID没有交叉的话,那就算重启也不会产生碎片,否则的话,重启后可能会有碎片。
    Please click the Mark as Answer button if a post solves your problem!



    2012年11月13日 2:54
  • Machine will generate random base guid every time rebooting, that's where the problem comes from because newsequentialid() generates new value based on current base id.
    2012年11月13日 3:04
  • 我测试过,重启的NEWSEQUENTIALID和上次的不会交叉。不过不保证和多次重启以前的也不交叉。根据guid的分布区间来说,我认为交叉的可能性不大。

    Anyway,楼主的这个case还是用bigint合适。


    想不想时已是想,不如不想都不想。

    2012年11月13日 6:30
    版主
  • 很有意思的讨论。

    我觉得NEWSEQUENTIALID不会有很大的性能问题,哪怕多次重启。NEWSEQUENTIALID在重启之后可能会产生交叉,但是就算有交叉,就算产生碎片,那对整个performance都不会产生实质性的影响。

    原因:

    1 如果没有交叉,重启后新产生的GUID跟原来的不交叉,那不会有碎片产生,性能就无影响。

    2 如果有交叉,有碎片,那碎片也是很少的,不影响整体性能。为什么呢?

    假如重启后新生成的GUID的起始值在原来的GUID之间,那么产生分页的也只有一次,后续插入的GUID不会再产生分页。

    比如原来有1个旧的页面,假设为PAGEID 2并且那页已经充满数据,假设重启后新生成的GUID的位置正好落在PAGEID为2的页面内,从而导致分页,那原来的PAGEID2 假设变成PAGEID 2跟PAGEID 3(PAGEID 3为拆分后新生成的页面),那么会产生一次分页,但也就那么一次而已,后续生成的页面都不会再拆分,因为后续生成的GUID都是连续的,既然是连续的,那么那些记录都存储在新的页面内,而不是再拆分其他的原有页面,假如后续陆续生成4,5,6 三个新的页面的数据,那么页面之间链表的顺序会是 2—>4->5->6—>3, 除了前面那一次拆分外,不会继续发生分页。

    所以说NEWSEQUENTIALID在重启后可能会产生分页(但只发生一次,且只有一页),所以对整体性能无影响。



    Please click the Mark as Answer button if a post solves your problem!

    2012年11月13日 7:43
  • 用bigint,如果bigint还会溢出,哪就不要用int,不自动增长,用字符串,在应用程序里面取出来后转换成int,插入时再转换成字符串,int和字符串转换这个也很容易的.

    2012年11月13日 9:35
  • 使用字符串聚集主键就失去意义了

    给我写信: QQ我:点击这里给我发消息

    2012年11月13日 12:01
  • 用bigint,如果bigint还会溢出,哪就不要用int,不自动增长,用字符串,在应用程序里面取出来后转换成int,插入时再转换成字符串,int和字符串转换这个也很容易的.


    不明白你的意思。


    Please click the Mark as Answer button if a post solves your problem!

    2012年11月13日 14:43
  • It can go to 9,223,372,036,854,775,807 in bigint column, anyone knows any table with that amount of rows?
    2012年11月13日 15:06