求陈奕迅四季无损下载的《一丝不挂》和《可以了》百度云,十分感谢

有关数据库设计中主键的设计原则和选取策略
有关数据库设计中主键的设计原则和选取策略
本文节选自网络博客:,仅供大家学习参考。
三、数据库中主键和外键的设计原则
主键和外键是把多个表组织为一个有效的关系数据库的粘合剂。主键和外键的设计对物理数据库的性能和可用性都有着决定性的影响。
必须将数据库模式从理论上的逻辑设计转换为实际的物理设计。而主键和外键的结构是这个设计过程的症结所在。一旦将所设计的数据库用于了生产环境,就很难对这些键进行修改,所以在开发阶段就设计好主键和外键就是非常必要和值得的。
& 关系数据库依赖于主键---它是数据库物理模式的基石。主键在物理层面上只有两个用途:
&&&&&&&&1.
惟一地标识一行。
&&&&&&&&2.
作为一个可以被外键有效引用的对象。
& 基于以上这两个用途,下面给出了我在设计物理层面的主键时所遵循的一些原则:
主键应当是对用户没有意义的。如果用户看到了一个表示多对多关系的连接表中的数据,并抱怨它没有什么用处,那就证明它的主键设计地很好。
2. 主键应该是单列的,以便提高连接和筛选操作的效率。
&&&&&&&注:使用复合键的人通常有两个理由为自己开脱,而这两个理由都是错误的。其一是主键应当具有实际意义,然而,让主键具有意义只不过是给人为地破坏数据库提供了方便。其二是利用这种方法可以在描述多对多关系的连接表中使用两个外部键来作为主键,我也反对这种做法,理由是:复合主键常常导致不良的外键,即当连接表成为另一个从表的主表,而依据上面的第二种方法成为这个表主键的一部分,然,这个表又有可能再成为其它从表的主表,其主键又有可能成了其它从表主键的一部分,如此传递下去,越靠后的从表,其主键将会包含越多的列了。
永远也不要更新主键。实际上,因为主键除了惟一地标识一行之外,再没有其他的用途了,所以也就没有理由去对它更新。如果主键需要更新,则说明主键应对用户无意义的原则被违反了。
&&&&&&&注:这项原则对于那些经常需要在数据转换或多数据库合并时进行数据整理的数据并不适用。
4. 主键不应包含动态变化的数据,如时间戳、创建时间列、修改时间列等。
主键应当有计算机自动生成。如果由人来对主键的创建进行干预,就会使它带有除了惟一标识一行以外的意义。一旦越过这个界限,就可能产生认为修改主键的动机,这样,这种系统用来链接记录行、管理记录行的关键手段就会落入不了解数据库设计的人的手中。
四、数据库主键选取策略
我们在建立数据库的时候,需要为每张表指定一个主键,所谓主键就是能够唯一标识表中某一行的属性或属性组,一个表只能有一个主键,但可以有多个候选索引。因为主键可以唯一标识某一行记录,所以可以确保执行数据更新、删除的时候不会出现张冠李戴的错误。当然,其它字段可以辅助我们在执行这些操作时消除共享冲突,不过就不在这里讨论了。主键除了上述作用外,常常与外键构成参照完整性约束,防止出现数据不一致。所以数据库在设计时,主键起到了很重要的作用。
常见的数据库主键选取方式有:
自动增长字段
手动增长字段
UniqueIdentifier
“COMB(Combine)”类型
1、自动增长型字段
很多数据库设计者喜欢使用自动增长型字段,因为它使用简单。自动增长型字段允许我们在向数据库添加数据时,不考虑主键的取值,记录插入后,数据库系统会自动为其分配一个值,确保绝对不会出现重复。如果使用SQL
Server数据库的话,我们还可以在记录插入后使用@@IDENTITY全局变量获取系统分配的主键键值。
尽管自动增长型字段会省掉我们很多繁琐的工作,但使用它也存在潜在的问题,那就是在数据缓冲模式下,很难预先填写主键与外键的值。假设有两张表:
Order(OrderID, OrderDate)
OrderDetial(OrderID, LineNum, ProductID, Price)
Order表中的OrderID是自动增长型的字段。现在需要我们录入一张订单,包括在Order表中插入一条记录以及在OrderDetail表中插入若干条记录。因为Order表中的OrderID是自动增长型的字段,那么我们在记录正式插入到数据库之前无法事先得知它的取值,只有在更新后才能知道数据库为它分配的是什么值。这会造成以下矛盾发生:
首先,为了能在OrderDetail的OrderID字段中添入正确的值,必须先更新Order表以获取到系统为其分配的OrderID值,然后再用这个OrderID填充OrderDetail表。最后更新OderDetail表。但是,为了确保数据的一致性,Order与OrderDetail在更新时必须在事务保护下同时进行,即确保两表同时更行成功。显然它们是相互矛盾的。
除此之外,当我们需要在多个数据库间进行数据的复制时(SQL
Server的数据分发、订阅机制允许我们进行库间的数据复制操作),自动增长型字段可能造成数据合并时的主键冲突。设想一个数据库中的Order表向另一个库中的Order表复制数据库时,OrderID到底该不该自动增长呢?
ADO.NET允许我们在DataSet中将某一个字段设置为自动增长型字段,但千万记住,这个自动增长字段仅仅是个占位符而已,当数据库进行更新时,数据库生成的值会自动取代ADO.NET分配的值。所以为了防止用户产生误解,建议大家将ADO.NET中的自动增长初始值以及增量都设置成-1。此外,在ADO.NET中,我们可以为两张表建立DataRelation,这样存在级联关系的两张表更新时,一张表更新后另外一张表对应键的值也会自动发生变化,这会大大减少了我们对存在级联关系的两表间更新时自动增长型字段带来的麻烦。
2、手动增长型字段
既然自动增长型字段会带来如此的麻烦,我们不妨考虑使用手动增长型的字段,也就是说主键的值需要自己维护,通常情况下需要建立一张单独的表存储当前主键键值。还用上面的例子来说,这次我们新建一张表叫IntKey,包含两个字段,KeyName以及KeyValue。就像一个HashTable,给一个KeyName,就可以知道目前的KeyValue是什么,然后手工实现键值数据递增。在SQL
Server中可以编写这样一个存储过程,让取键值的过程自动进行。代码如下:
CREATE&PROCEDURE&[GetKey]
@KeyName&char(10),&
@KeyValue&int&OUTPUT&
UPDATE&IntKey&SET&@KeyValue&=&KeyValue&=&KeyValue&+&1&WHERE&KeyName&=&@KeyName
这样,通过调用存储过程,我们可以获得最新键值,确保不会出现重复。若将OrderID字段设置为手动增长型字段,我们的程序可以由以下几步来实现:首先调用存储过程,获得一个OrderID,然后使用这个OrderID填充Order表与OrderDetail表,最后在事务保护下对两表进行更新。
使用手动增长型字段作为主键在进行数据库间数据复制时,可以确保数据合并过程中不会出现键值冲突,只要我们为不同的数据库分配不同的主键取值段就行了。但是,使用手动增长型字段会增加网络的RoundTrip,我们必须通过增加一次数据库访问来获取当前主键键值,这会增加网络和数据库的负载,当处于一个低速或断开的网络环境中时,这种做法会有很大的弊端。同时,手工维护主键还要考虑并发冲突等种种因素,这更会增加系统的复杂程度。
3、使用UniqueIdentifier
SQL Server为我们提供了UniqueIdentifier数据类型,并提供了一个生成函数NEWID( ),使用NEWID(
)可以生成一个唯一的UniqueIdentifier。UniqueIdentifier在数据库中占用16个字节,出现重复的概率非常小,以至于可以认为是0。我们经常从注册表中看到类似
{45F0EB02-E-AAB5-E8AEDEE0CEC5}
的东西实际上就是一个UniqueIdentifier,Windows用它来做COM组件以及接口的标识,防止出现重复。在.NET里管UniqueIdentifier称之为GUID(Global
Unique Identifier)。在C#中可以使用如下命令生成一个GUID:
Guid&u&=&System.Guid.NewGuid();
对于上面提到的Order与OrderDetail的程序,如果选用UniqueIdentifier作为主键的话,我们完全可以避免上面提到的增加网络RoundTrip的问题。通过程序直接生成GUID填充主键,不用考虑是否会出现重复。
UniqueIdentifier字段也存在严重的缺陷:首先,它的长度是16字节,是整数的4倍长,会占用大量存储空间。更为严重的是,UniqueIdentifier的生成毫无规律可言,要想在上面建立索引(绝大多数数据库在主键上都有索引)是一个非常耗时的操作。有人做过实验,插入同样的数据量,使用UniqueIdentifier型数据做主键要比使用Integer型数据慢,所以,出于效率考虑,尽可能避免使用UniqueIdentifier型数据库作为主键键值。
4、使用“COMB(Combine)”类型
既然上面三种主键类型选取策略都存在各自的缺点,那么到底有没有好的办法加以解决呢?答案是肯定的。通过使用COMB类型(数据库中没有COMB类型,它是Jimmy
Nilsson在他的“The Cost of GUIDs as Primary
Keys”一文中设计出来的),可以在三者之间找到一个很好的平衡点。
COMB数据类型的基本设计思路是这样的:既然UniqueIdentifier数据因毫无规律可言造成索引效率低下,影响了系统的性能,那么我们能不能通过组合的方式,保留UniqueIdentifier的前10个字节,用后6个字节表示GUID生成的时间(DateTime),这样我们将时间信息与UniqueIdentifier组合起来,在保留UniqueIdentifier的唯一性的同时增加了有序性,以此来提高索引效率。也许有人会担心UniqueIdentifier减少到10字节会造成数据出现重复,其实不用担心,后6字节的时间精度可以达到1/300秒,两个COMB类型数据完全相同的可能性是在这1/300秒内生成的两个GUID前10个字节完全相同,这几乎是不可能的!在SQL
Server中用SQL命令将这一思路实现出来便是:
DECLARE&@aGuid&UNIQUEIDENTIFIER
SET&@aGuid&=&CAST(CAST(NEWID()&AS&BINARY(10))&
+&CAST(GETDATE()&AS&BINARY(6))&AS&UNIQUEIDENTIFIER)
经过测试,使用COMB做主键比使用INT做主键,在检索、插入、更新、删除等操作上仍然显慢,但比Unidentifier类型要快上一些。关于测试数据可以参考我日的随笔。
除了使用存储过程实现COMB数据外,我们也可以使用C#生成COMB数据,这样所有主键生成工作可以在客户端完成。C#代码如下:
//================================================================
///&summary&
///&返回&GUID&用于数据库操作,特定的时间代码可以提高检索效率
///&&/summary&
///&&returns&COMB&(GUID&与时间混合型)&类型&GUID&数据&/returns&
public&static&Guid&NewComb()&
&&&&&byte[]&guidArray&=&System.Guid.NewGuid().ToByteArray();&
&&&&&DateTime&baseDate&=&new&DateTime();&
&&&&&DateTime&now&=&DateTime.N&
&&&&&//&Get&the&days&and&milliseconds&which&will&be&used&to&build&the&byte&string&
&&&&&TimeSpan&days&=&new&TimeSpan(now.Ticks&-&baseDate.Ticks);&
&&&&&TimeSpan&msecs&=&new&TimeSpan(now.Ticks&-&(new&DateTime(now.Year,&now.Month,&now.Day).Ticks));&
&&&&&//&Convert&to&a&byte&array&
&&&&&//&Note&that&SQL&Server&is&accurate&to&1/300th&of&a&millisecond&so&we&divide&by&3.333333&
&&&&&byte[]&daysArray&=&BitConverter.GetBytes(days.Days);&
&&&&&byte[]&msecsArray&=&BitConverter.GetBytes((long)(msecs.TotalMilliseconds/3.333333));&
&&&&&//&Reverse&the&bytes&to&match&SQL&Servers&ordering&
&&&&&Array.Reverse(daysArray);&
&&&&&Array.Reverse(msecsArray);&
&&&&&//&Copy&the&bytes&into&the&guid&
&&&&&Array.Copy(daysArray,&daysArray.Length&-&2,&guidArray,&guidArray.Length&-&6,&2);&
&&&&&Array.Copy(msecsArray,&msecsArray.Length&-&4,&guidArray,&guidArray.Length&-&4,&4);&
&&&&&return&new&System.Guid(guidArray);&
//================================================================
///&&summary&
///&从&SQL&SERVER&返回的&GUID&中生成时间信息
///&&/summary&
///&&param&name="guid"&包含时间信息的&COMB&&/param&
///&&returns&时间&/returns&
public&static&DateTime&GetDateFromComb(System.Guid&guid)&
&&&&&DateTime&baseDate&=&new&DateTime();&
&&&&&byte[]&daysArray&=&new&byte[4];&
&&&&&byte[]&msecsArray&=&new&byte[4];&
&&&&&byte[]&guidArray&=&guid.ToByteArray();&
&&&&&//&Copy&the&date&parts&of&the&guid&to&the&respective&byte&arrays.&
&&&&&Array.Copy(guidArray,&guidArray.Length&-&6,&daysArray,&2,&2);&
&&&&&Array.Copy(guidArray,&guidArray.Length&-&4,&msecsArray,&0,&4);&
&&&&&//&Reverse&the&arrays&to&put&them&into&the&appropriate&order&
&&&&&Array.Reverse(daysArray);&
&&&&&Array.Reverse(msecsArray);&
&&&&&//&Convert&the&bytes&to&ints&
&&&&&int&days&=&BitConverter.ToInt32(daysArray,&0);&
&&&&&int&msecs&=&BitConverter.ToInt32(msecsArray,&0);&
&&&&&DateTime&date&=&baseDate.AddDays(days);&
&&&&&date&=&date.AddMilliseconds(msecs&*&3.333333);&
&&&&&return&&
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。1. 主键定义... 5
2. 主键设计原则... 5
2.1 确保主键的无意义性... 5
2.2 采用整型主键... 5
2.3 减少主键的变动... 5
2.4 避免重复使用主键... 6
2.5 主键字段定义区分... 6
3. 主键方案... 6
3.1 自增ID.. 6
3.2 UUID.. 7
3.3 ID物理主键+UUID逻辑主键... 7
4. 总结... 8
1. 主键定义
表中经常有一个列或多列的组合,其值能唯一地标识表中的每一行。这样的一列或多列称为表的主键,通过它可强制表的实体完整性。
2. 主键设计原则
总原则:根据数据库表的具体使用范围来决定采用不同的表主键定义。
2.1 确保主键的无意义性
&&&&&&&& 在开发过程中,有意义的字段例如&用户登录信息表&将&登录名&(英文名)作为主键,&订单表&中将&订单编号&作为主键,如此设计主键一般都是没什么问题,因为将这些主键基本不具有&意义更改&的可能性。
但是,也有一些例外的情况,例如&订单表&需要支持需求&订单可以作废,并重新生成订单,而且订单号要保持原订单号一致&,那将&订单编号&作为主键就满足不了要求了。
因此在使用具有实际意义的字段作为主键时,需要考虑是否存在这种可能性。
要用代理主键,不要使用业务主键。任何一张表,强烈建议不要使用有业务含义的字段充当主键。我们通常都是在表中单独添加一个整型的编号充当主键字段。
2.2 采用整型主键
主键通常都是整数,不建议使用字符串当主键。(如果主键是用于集群式服务,可以采用字符串类型)
2.3 减少主键的变动
?&&&&&& 主键的值通常都不允许修改,除非本记录被删除。
2.4 避免重复使用主键
?&&&&&& 主键的值通常不重用,意味着记录被删除后,该主键值不再使用。
2.5 主键字段定义区分
主键不要直接定义成【id】,而要加上前缀,定义成【表名id】或者【表名_id】
3. 主键方案
3.1 自增ID
n& 数据库自动编号,速度快,而且是增量增长,聚集型主键按顺序存放,对于检索非常有利。
n& 数字型,占用空间小,易排序,在程序中传递方便。
n& 当系统与其他系统集成时,需要数据导入时,很难保证原系统的ID不发生主键冲突。在多个数据库间进行数据的复制时(SQL Server的数据分发、订阅机制允许我们进行库间的数据复制操作),自动增长式字段可能造成数据合并时的主键冲突及表关联关系的丢失。
n& 如果其他系统主键不是数字型,会导致修改主键数据类型,导致其他相关表的修改。
n& 在数据缓冲模式下,很难预先填写主键与外键的值。
n& 自增量的值都是需要在系统中维护一个全局的数据值,每次插入数据时即对此次值进行增量取值。当在产生唯一标识的并发环境中,每次的增量取值都必须为此全局值加锁解锁以保证增量的唯一性。造成并发瓶颈,降低查询性能。每创建一条记录都需要对表加一次锁,在高并发环境下开销较大。
UUID是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。在UUID的算法中,可能会用到诸如网卡MAC地址,IP,主机名,进程ID等信息以保证其独立性。
n& 全局唯一性、安全性、可移植性。
n& 能够保证独立性,程序可以在不同的数据库间迁移,效果不受影响。
n& 保证生成的ID不仅是表独立的,而且是库独立的,在你切分数据库的时候尤为重要。
n& InnoDB为聚集主键类型的引擎,数据会按照主键进行排序,由于UUID的无序性,InnoDB会产生巨大的IO压力。InnoDB主键索引和数据存储位置相关(簇类索引),uuid 主键可能会引起数据位置频繁变动,严重影响性能。
n& 作为主键,UUID长度过长,主键索引KeyLength长度过大,而影响能够基于内存的索引记录数量,进而影响基于内存的索引命中率,而基于硬盘进行索引查询性能很差。严重影响数据库服务器整体的性能表现。
3.3 ID物理主键+UUID逻辑主键
InnoDB不适合使用UUID做物理主键,可以把它作为逻辑主键,物理主键依然使用自增ID。
主键仍然用auto_increment_int来做,而另加一个uuid做唯一索引,表外键关联什么的,还 用uuid来做,也就是说auto_increment_int只是一个形式上的主键,而uuid才是事实上的主键,这样,一方面int主键不会浪费太多空间,另一方面,还可以继续使用uuid。
n& InnoDB会对主键进行物理排序,这对auto_increment_int类型有好处,因为后一次插入的主键位置总是在最后。但是对uuid来说则有缺点,因为uuid是杂乱无章的,每次插入的主键位置是不确定的,可能在开头,也可能在中间,在进行主键物理排序的时候,势必会造成大量的 IO操作影响效率。
n& 同自增ID的缺点:全局值加锁解锁以保证增量的唯一性带来的性能问题。
&&&&&&&& 本文主要针对MySQL数据库中的InnoDB存储引擎的主键设计原则进行调研,挑选了几种主流的主键方案进行优缺点的分析和对比,并最终建议选择自增ID作为物理主键,同时使用UUID作为逻辑主键的方案。
如果一些特殊的表,比如说日志表,其不需要维护,可以采用数据库自动增长ID的方式。这种方式性能好,产生也很方便。但是维护很麻烦。
阅读(...) 评论()MySQL(7)
数据库主键设计之思考一
1.是否要采用GUID作为主键
用GUID作主键有它的优势与不足.优势是GUID具有唯一性,在任何情况下,可以产生全球唯一的值.这是GUID&最大的优势,也方便数据导入,比如要求从另一个系统中把数据导入进来,那么,不用担心,导入时,会导致主键冲突.不足是GUID值太复杂.不易记忆,因为&有时,难免我们会用记录的方式,来进行记录判断.而且数据太长,影响数据库效率.GUID的产生不是以一定的次序产生,对于按主键物理排序的数据库来说,&如果在记录的前部插入一条记录,可能会导致后面N次方的数据条数后移.这将导致数据插入效率.因此GUID的采用应该要慎重.
2.是否要采用自动递增的方式
对于以前谈到的主键,要求唯一性,因此大家都用自动递增的方式.这样的方式是非常不可取的.可能是为了方便插入记录&时,不必去人为创建主键值.以为这样会方便,其实不是的.带来的麻烦要远远胜于这种所谓的&方便&.第一:数据导入不方便,经常会有从另一系统导入数据进&来,自动递增的主键,将不允许原表中的ID被导入进来.这会导致主键丢失.第二:对于象订单这样的有主外键的表来说,如果订单的&主档表&主键是自动生成&的.那么在保存一个订单时,会要求对主档表与明细表同进行事务保存,而此时,先要生成一条订单,然后取出这个订单自动生成的主键,然后再把此作为明细表的&一个外键,进行明细的保存.这过程中,将变以复杂而且不可行.事务如何处理.订单主档表插入记录后,要是明细保存时遇到错误,主档表记录还要进行删除.&烦.插入成功以后,还要取出产生的最大值.这将是一个严重的浪费.记录多的话会影响速度,而且会存在并行插入.导致获取的记录可能是不正确的.&&&因此在以上的严重问题下,请不要采用自动递增方式.
3.是否要采用int型作为主键
以前大家都采用int型,都是出来主键都是数字导致的.其实我们也明白.并不是只是数字的东西就是数字型的.比如电&话号码等.因此对于主键,采用int型的优势是速度快,插入,查询时都可能会比其他的方式快.但我这种快的效果也未必有多明显,比如以varchar(15)为例,物理主键排序的数据,会自动以主键进行物理数据排序.因此,就算是字符型的数据,在插入时也会插入到相应的物理位置上,也就&是说,在插入时可能会影响一些速度.但在以后的查询中,速度影响不会太明显.而我要说的,不采用int型作为主键,不是说,里面不存数据.我还是建议大家&在主键中存放数字,这样的排序比较要比夹杂字母的排序来的快,之所以要采用字符型,也是为以后的数据导入作准备,有一天,会要求从其他表导入数据时,可以&在导入数据的主键上加一个特定字母来避免与原主键冲突.比如在导入数据的主键前加一个"N"字母.这也就不用担心,要求导入数据表中的主键是数字型还是字&符型了.
4.是否采用编号来定义主键
这个问题是老生常谈了.主键设计有个原则,就是主键不应具有任何实际意义.这条其实是非常重要,有人就是觉得编号本&身是唯一的,可以作为主键用,但可能会为以后带来麻烦.因为带有实际意义的字段,还是存在被修改的可能性.而对于主键最大的忌讳就是修改主键,这可能会导&致非常严重的不可估计的后果.比如学生编号,平时以为永远不会修改,但修改的可能还是会存在.
还有一种,表面上是唯一的,但实际上应该是允许重复的.我举个例子,订单吧,订单编号应该是唯一吧.是的.可是会存&在这样的情况,一张原来的订单是因为某个原因,要求订单作废.那好给订单的状态标识为"cancel".然后允许再次录入同样编号的订单.因此.对于这样&的情况下在,虽然有效的订单编号只有一个,但在数据库角度会允许编号重复.所以不管如何,还是建议大家为表都建一个没有任何意义的主键,如ID.
因此,总结一下,在设计主键,会采用字符型的.不采用自动递增,在新增记录时,系统生成主键值.一般为全数字进行存&入,至于主键值的生成规则,可以按需求进行规则定义.如果没有特殊的要求,只是为了保持唯一,可以定义一个字段存放一个数值.在生成时,自动加一.然后再&存回去.这也比从一个表中寻找最大值要来的快吧.
数据库主键设计之思考二
主键的必要性:
&&&&有些朋友可能不提倡数据库表必须要主键,但在我的思考中,觉得每个表都应该具有主键,不管是单主还是双主键,主键的存在就代表着表结构的完整性,表的记录&必须得有唯一区分的字段,主键主要是用于其他表的外键关联,本记录的修改与删除,当我们没有主键时,这些操作会变的非常麻烦。
主键的无意义性:
&&&&我强调主键不应该具有实际的意义,这可能对于一些朋友来说不太认同,比如订单表吧,会有“订单编号”字段,而这个字段呢在业务实际中本身就是应该具有唯一&性,具有唯一标识记录的功能,但我是不推荐采用订单编号字段作为主键的,因为具有实际意义的字段,具有“意义更改”的可能性,比如订单编号在刚开始的时候&我们一切顺利,后来客户说“订单可以作,并重新生成订单,而且订单号要保持原订单号一致”,这样原来的主键就面临危险了。因此,具有唯一性的实际字段也代&表可以作为主键。因此,我推荐是新设一个字段专门用为主键,此主键本身在业务逻辑上不体现,不具有实际意义。而这种主键在一定程序增加了复杂度,所以要视&实际系统的规模大小而定,对于小项目,以后扩展不会很大的话,也查允许用实际唯一的字段作主键的。
主键的选择
&&&&我们现在在思考一下,应该采用什么来作表的主键比较合理,申明一下,主键的设计没有一个定论,各人有各人的方法,哪怕同一个,在不同的项目中,也会采用不同的主键设计原则。
第一:编号作主键
&&&&&此方法就是采用实际业务中的唯一字段的“编号”作为主键设计,这在小型的项目中是推荐这样做的,因为这可以使项目比较简单化,但在使用中却可能带来一些麻&烦,比如要进行编号修改”时,可能要涉及到很多相关联的其他表,就象黎叔说的“后果很严重”;还有就是上面提到的“业务要求允许编号重复时”,我们再那么&先知,都无法知道业务将会修改成什么?
第二:自动编号主键
&&&&&&这种方法也是很多朋友在使用的,就是新建一个ID字段,自动增长,非常方便也满足主键的原则,优点是:数据库自动编号,速度快,而且是增量增长,聚集型主&键按顺序存放,对于检索非常有利;数字型的,占用空间小,易排序,在程序中传递也方便;如果通过非系统增加记录(比如手动录入,或是用其他工具直接在表里&插入新记录,或老系统数据导入)时,非常方便,不用担心主键重复问题。
&&&&&&缺点:其实缺点也就是来自其优点,就是因为自动增长,在手动要插入&指定ID的记录时会显得麻烦,尤其是当系统与其他系统集成时,需要数据导入时,很难保证原系统的ID不发生主键冲突(前提是老系统也是数字型的);如果其&他系统主键不是数字型那就麻烦更大了,会导致修改主键数据类型了,这也会导致其他相关表的修改,后果同样很严重;就算其他系统也是数字型的,在导入时,为&了区分新老数据,可能想在老数据主键前统一加一个“o”(old)来表示这是老数据,那么自动增长的数字型又面临一个挑战。
第三:Max加一
&&&&&由于自动编号存在那些问题,所以有些朋友就采用自己生成,同样是数字型的,只是把自动增长去掉了,采用在Insert时,读取Max值后加一,这种方法可&以避免自动编号的问题,但也存在一个效率问题,如果记录非常大的话,那么Max()也会影响效率的;更严重的是并发性问题,如果同时有两人读到相同的Max后,加一后插入的ID值会重复,这已经是有经验教训的了。
第四:自制加一
&&&&&考虑Max加一的效率后,有人采用自制加一,也就是建一个特别的表,字段为:表名,当前序列值。这样在往表中插入值时,先从此表中找到相应表的最大值后加&一,进行插入,有人可能发现,也可能会存在并发处理,这个并发处理,我们可以采用lock线程的方式来避免,在生成此值的时,先Lock,取到值以后,再unLock出来,这样不会有两人同时生成了。这比Max加一的速度要快多了。但同样存在一个问题:在与其他系统集成时,脱离了系统中的生成方法后,很麻&烦保证自制表中的最大值与导入后的保持一致,而且数字型都存在上面讲到的“o”老数据的导入问题。因此在“自制加一”中可以把主键设为字符型的。字符型的&自制加一我倒是蛮推荐的,应该字符型主键可以应付很多我们意想不到的情况。
第五:GUID主键
&&&&目前一个比较好的主键是采用GUID,当然我是推荐主键还是字符型的,但值由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&键,可能会带来两方面的消极影响:存储空间增大;索引时间较慢。
&&&&我也不是推荐GUID最好,其实在不同的情况,我们都可以采用上面的某一种方式,思考了一些利与弊,也方便大家在进行设计时参考。这些也只是我的一点思考而已,而且可能我知识面限制,会有一些误论在里面,希望大家有什么想法欢迎讨论。
数据库外键设计之思考
外键的目的:通过数据库去保证数据的完整性,提高关联查询的效率副作用:插入或更新的效率下降。
通过数据库保证数据完成性。两个表关联查询很多的时候,并且数据量很大,可以不考虑插入或更新的效率时候。
2。可用,可以不用
可以忍受数据不完整性。或认为程序已经可以控制数据的完整性。
两个表关联查询很多的时候,但两个表的数据量不大或两个表关联查询很多,对查询效率不高,对插入或更新的效率要求高,
两个表无任何逻辑关系,对插入或更新效率要求及高
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:56431次
积分:1584
积分:1584
排名:第19934名
原创:91篇
转载:31篇
评论:37条
(9)(9)(20)(9)(22)(14)(15)(6)(1)(12)(3)(5)

我要回帖

更多关于 陈奕迅你的背包百度云 的文章

 

随机推荐