主键的选择

来源:互联网 发布:张龙 java 编辑:程序博客网 时间:2024/06/04 23:33

        Recently we are going on the School System(教务系统)。Our group is in charge of the Basic Information part.设计和操作数据库,is almost our whole work.

        设计数据库阶段,首先,分析需要建哪些表,每张表设计哪些字段;再设计主键和外键,修改和完善数据库。

        When I came to the Primary Key, something puzzled me:有些主键,比如xx记录表,主键是int自增类型;而有些,我们选择用编号来作为主键(比如楼号,学号)。然后问题来了,用编号作为主键,当该条信息修改时,以前的记录就被冲掉了,可是我想在数据库保留存在过的所有记录。Well,may be I go wrong.

        但是,忽略这两种选择方式,他们都是主键。那么什么是主键,它存在的意义在哪里,它又是做什么的呢?

        主键,“主关键字(primary key)是表中的一个或多个字段,它的值用于惟一地标识表中的某一条记录”。

        作用:(1)唯一区分每条记录的字段;(2)本记录的修改与删除;(3)用于其它表的外键关联。当我们没有主键时,这些操作会变的非常麻烦。

        在我的意识中,每张表都应该有它的主键,主键的存在代表着表结构的完整性。

        那么,怎样选择主键??读到一篇文章,提到主键的选择:

       (1)编号

        采用实际业务中的唯一字段的“编号”作为主键设计,这在小型的项目中是推荐这样做的,因为这可以使项目比较简单化,但在使用中却可能带来一些麻烦。比如上面提到的修改数据时,只能保存现有数据,而不能保存历史数据。还有,要进行“编号修改”时,可能要涉及到很多相关联的其他表,“后果很严重”,当然我们尽量避免。       (2)自动增长

         就是新建一个ID字段,自动增长。自动增长型字段允许我们在向数据库添加数据时,不考虑主键的取值,记录插入后,数据库系统会自动为其分配一个值,确保绝对不会出现重复。使用SQL Server数据库,我们还可以在记录插入后使用@@IDENTITY全局变量获取系统分配的主键键值。

         优点:数据库自动编号,速度快,而且是增量增长,聚集型主键按顺序存放,对于检索非常有利;数字型的,占用空间小,易排序,在程序中传递也方便;如果通过非系统增加记录(比如手动录入,或是用其他工具直接在表里插入新记录,或老系统数据导入)时,非常方便,不用担心主键重复问题。

         缺点:其实缺点也就是来自其优点,就是因为自动增长,在手动要插入指定ID的记录时会显得麻烦,尤其是当系统与其他系统集成时,需要数据导入时,很难保证原系统的ID不发生主键冲突(前提是老系统也是数字型的);如果其他系统主键不是数字型那就麻烦更大了,会导致修改主键数据类型了,这也会导致其他相关表的修改,后果同样很严重;就算其他系统也是数字型的,在导入时,为了区分新老数据,可能想在老数据主键前统一加一个“o”(old)来表示这是老数据,那么自动增长的数字型又面临一个挑战。

       (3)Max加一

        由于自动编号存在那些问题,所以有些朋友就采用自己生成,同样是数字型的,只是把自动增长去掉了,采用在Insert时,读取Max值后加一,这种方法可以避免自动编号的问题,但也存在一个效率问题,如果记录非常大的话,那么Max()也会影响效率的;更严重的是并发性问题,如果同时有两人读到相同的Max后,加一后插入的ID值会重复。

       (4)自制加一

        考虑Max加一的效率后,有人采用自制加一,也就是建一个特别的表,字段为:表名,当前序列值。这样在往表中插入值时,先从此表中找到相应表的最大值后加一,进行插入。有人可能发现,也可能会存在并发处理,这个并发处理,我们可以采用lock线程的方式来避免,在生成此值的时,先Lock,取到值以后,再unLock出来,这样不会有两人同时生成了。这比Max加一的速度要快多了。

        但同样存在一个问题:在与其他系统集成时,脱离了系统中的生成方法后,很麻烦保证自制表中的最大值与导入后的保持一致,而且数字型都存在上面讲到的“o”老数据的导入问题。因此在“自制加一”中可以把主键设为字符型的。字符型的自制加一我倒是蛮推荐的,应该字符型主键可以应付很多我们意想不到的情况。

       (5)GUID主键

         GUID是可以自动生成,也可以程序生成,而且键值不可能重复,可以解决系统集成问题,几个系统的GUID值导到一起时,也不会发生重复,就算有“o”老数据也可以区分,而且效率很高,在.NET里可以直接使用System.Guid.NewGuid()进行生成,在SQL里也可以使用 NewID()生成。

        优点是:

        同 IDENTITY 列相比,uniqueidentifier 列可以通过 NewID() 函数提前得知新增加的行 ID,为应用程序的后续处理提供了很大方便。

        便于数据库移植,其它数据库中并不一定具有 IDENTITY 列,而 Guid 列可以作为字符型列转换到其它数据库中,同时将应用程序中产生的 GUID 值存入数据库,它不会对原有数据带来影响。

        便于数据库初始化,如果应用程序要加载一些初始数据, IDENTITY 列的处理方式就比较麻烦,而 uniqueidentifier 列则无需任何处理,直接用 T-SQL 加载即可。

        便于对某些对象或常量进行永久标识,如类的 ClassID,对象的实例标识,UDDI 中的联系人、服务接口、tModel标识定义等。

        缺点是:

        GUID 值较长,不容易记忆和输入,而且这个值是随机、无顺序的

        GUID 的值有 16 个字节,与其它那些诸如 4 字节的整数相比要相对大一些。这意味着如果在数据库中使用 uniqueidentifier 键,可能会带来两方面的消极影响:存储空间增大;索引时间较慢。

原创粉丝点击