SQL反模式(三)

2013-02-19 01:20

SQL反模式(三)

by snoopyxdy

at 2013-02-18 17:20:31

original http://snoopyxdy.blog.163.com/blog/static/60117440201311823734902

案例3、主键
最近一个程序员问我:“如何阻止表中的重复项”,一开始我认为是他的表中缺少主键,后来发现不是那样。他的内容管理数据库存储了一个网站上所发表的文章,然后他使用交叉表来存储文章和标签之间多对多的关系。
SQL反模式(三) - snoopyxdy - snoopyxdy的博客
在数据表中出现了如下的记录:
SQL反模式(三) - snoopyxdy - snoopyxdy的博客
 所以出现了重复项

解决方案是对另外两列进行UNIQUE约束,但是这样,作为主键的id有些多余。

每个了解数据库的程序员都知道主键对于一张表来说是一个很重要的甚至必要的部分,主键是好的设计的一部分。难点是选择哪一列作为主键,大多数表中的每个属性的值都可能被很多行使用,引入一个无意义的新列作为主键这种类型的主键称为伪主键和代理键。

真的需要主键吗?
1、主键能确保一张表中不会出现重复行
2、在查询中应用单行的记录
3、支持外键
一个没有主键的表就好像MP3听歌,没有歌名一样,无法找到想听的歌,也无法保证歌曲不重复。

意义不明的关键字,我们非常习惯在数据表中添加一个名为id的字段作为自然增长的主键,但是列名id不会使查询更加清晰。如果在bug表增加bug_id或者在用户表,使用account_id事情就会变得很简单。

我们使用sql来join两张表的查询:
SELECT * FROM Bugs AS b JOIN BugsProducts AS bp ON (b.bug_id = bp.bug_id);
如果列名相同可以更简洁的使用using
SELECT * FROM Bugs JOIN BugsProducts USING (bug_id);

解决方案,使用组合主键:
SQL反模式(三) - snoopyxdy - snoopyxdy的博客
数据库会自动将重复项帮我们屏蔽


案例4、引用完整性:
关系型数据库的设计基本上可以说就是每张独立表之间的关系设计,引用完整性是合理的数据库设计和操作的重要一部分。当一列声明了外键约束之后,这些列中的数据必须在其父表的主键或者唯一字段的列存在。

可能有如下几点不使用外键的原因:
1、数据更新可能和约束有冲突
2、数据库使用外键会影响性能
3、当前数据库不支持外键
4、定义外键的语法不简单,需要查阅

省略外键能使数据库设计更加简单灵活或者高效,但是你不得不在其他地方付出代价,必须用额外的代码来维护引用完整性。

每次插入数据时要确保所引用的值在对应表中是存在的,每次删除时要保证所有相关表都要及时更新。要避免没有外键约束的情况下插入一条数据就要执行一次额外的select查询,检查被引用记录是否存在。要删除时要多次查询确认没有其他记录引用了该条记录。

解决方案,支持同步修改:
SQL反模式(三) - snoopyxdy - snoopyxdy的博客
 不需要在更新或者删除前执行select检查、不需要在同步时锁住整张表,也不需要定期执行脚本来清理一些孤立的数据



案例4、取整错误:
老板要求你根据每个程序员修复每个bug所花费的时间,来计算出关于项目开发的时间成本表,每个在accounts表中的程序员都有不同的时薪,因此你统计出每个程序员花在修复每个bug上的时间,然后乘以他们的时薪。
要实现这样的功能,需要新建开销的列,精确的统计这些开销,你决定将这些定义为FLOAT。
第二天老板对你说,这些数字不正确!
 
大多数编程语言都支持float和double,sql也是用相同的关键字支持类似的数据类型。很多程序员很自然的会在需要使用浮点数的地方使用sql的float类型。
就算我们再提高精度也不能将3个1/3的浮点数加起来达到1,只能无限接近1,比如
0.333333 + 0.333333 + 0.333333 = 0.999999

我们在数据库插入如下数据和表设计:
SQL反模式(三) - snoopyxdy - snoopyxdy的博客
 
SQL反模式(三) - snoopyxdy - snoopyxdy的博客
 
你会发现执行上述sql语句,什么都没有返回,我们需要在数据库设计时将精度也设置进去:

SQL反模式(三) - snoopyxdy - snoopyxdy的博客
 
然后我们再执行sql语句:
SQL反模式(三) - snoopyxdy - snoopyxdy的博客
 
就可以查到结果了,sql server 2010 这个问题已经不存在了