开发反模式(GUID) - 伪键洁癖
一、目标:整理数据
有的人有强迫症,他们会为一系列数据的断档而抓狂。

一方面,Id为3这一行确实发生过一些事情,为什么这个查询不返回Id为3的这一行?这条记录数据丢失了吗?那个Column到底是什么?我要为这条数据的丢失负责吗?
二、反模式:填充角落
大多数人对于断档的第一反应就是想要填补其中的空缺。对此,可能有两种做法:
1、不按照顺序分配编号
你可能想要在插入新行时,通过遍历表,将找到的第一个未分配的主键编号分配给新行,来代替原来自动分配的伪主键机制。随着你不断地插入新行,断档就被填补起来了。

然而,为了找到第一个未被使用的值,你不得不执行一次自联合查询:
SELECT TOP 1 c1.ColumnId + 1
FROM [Columns] AS c1
LEFT OUTER JOIN [Columns] AS c2 ON (c1.ColumnId + 1 = c2.ColumnId)
WHERE c2.ColumnId IS NULL
ORDER BY c1.ColumnId
如果用SELECT MAX(ColumnId) + 1 这种查询语句,则会出现并发访问的问题,如果有两个程序同时想要找最小的未使用值时,也会出现同样的问题,结果就是一个成功
,另一个失败。况且,这个方法既低效,也容易导致问题。
UPDATE [Columns] SET ColumnId = 3 WHERE ColumnId = 4
2、为现有行重新编号
在某些情况下,你可能急着想要让所有的主键变得连续,而等着新行来填补空缺不够快。你可能会考虑更新现有行的主键值,让其变得连续,从而消除断档。通常这样的做法是找到主键最大的行,然后用最小的未被使用的值来更新它。比如,你可以将4更新为3:

要完成这一步,你需要使用和前面一种方法插入新行类似的方法。先找到一个未被使用的值,随后执行UPDATE语句来重新分配主键值。这两步都会引起并发访问的问题。而且,你需要重复执行很多次这样的操作,才能将较大的断档填满。
你必须同时更新所有引用了你重新分配了主键的行的子记录。如果你在定义外键时,使用了ON UPDATE CASCADE选项,这一步会变得很方便,但如果你没这么做,就必须先禁用约束,手动更新所有的子记录,然后恢复约束。这是一个费时费力且容易出错的操作,并且可能会影响到数据库的服务,正常人都会避免这么做。
即使你完成了清理操作,“整洁”也是个“短命鬼”,如果如果Id是自动生成的,那么对不起,你懂的,Id自增还是按照原来的最大数值增加,比如最大是4,你将4改成了3,但是下一个自动生成的主键依然是5。
3、制造数据差异
重用主键并不是一个好主意,因为断档往往是由于一些合理的删除或者回滚数据引起的。假设一个AccountId为789的用户由于发送带有政治问题的邮件而被封号,产品策略要求删除了这个账号,如果你重用了主键,就会在某一时间点将789分配给另一个用户。而收件人可能在删除后的某一个时间点才打开这些邮件,他们还会投诉789这个Id账号的用户。尽管这个用户本身没有做错任何事情,但是它被分配了一个需要为此负责的编号。
三、解决方案:克服心理障碍
1、定义行号
大多数伪键返回的数字看起来就和行号一样,因为他们就是一次递增的,但这只是由于伪键实现机制所造成的巧合而已。按照这样的方式生成的主键值能比较方便地确保唯一性。
别把主键值和行号混为一谈。主键是用来标识表中记录的,而行号是用来标识查询结果集中记录的。查询结果集的行号和主键值没有一丁点关系,尤其是当你使用了JOIN、GROUP BY或者ORDER BY这些操作符的时候。
有很多使用行号的好理由,比如返回一个查询结果集的子集。通常我们称之为分页,就像在网络搜索时的一页。要选择一个子集,你需要使用到实际的连续增长的行号,但和查询的形式无关。
SQL Server定义了包括ROW_NUMBER()在内的一些窗口函数,返回一个查询结果集中一段连续的行。通常使用行号的作用是将查询结果限制在一个特定的范围内。

2、使用GUID
当然我们还可以生成随机伪键值,只要你不会重复使用任何数字。有些数据库提供全局唯一标识符(GUID)来达到这个目的。
GUID是一个128位的伪随机数(通常用32个),由于GUID的定义及其所要实现的目的,它被设计成具有唯一,因此你可以用其作为伪键。
下面给出用SQL Server使用GUID作为主键的例子:
CREATE TABLE Person(
Id UNIQUEIDENTIFIER DEFAULT NEWID(),
Name nvarchar(50)
)
效果如下:

使用GUID相对于整型自增主键来说有如下两个优势:
- 可以在多个数据库服务器上并发地生成伪键,而不用担心生成同样的值。
- 没有人会在抱怨有断档-他们会忙于抱怨输入32个十六进制字符做主键。
下面是使用GUID带来的不便:
- GUID的值太长,不便于输入。
- GUID的值是随机的,因此找不到任何规则或者依靠最大值来判断哪一行是最新插入的。
- GUID的存储需要16字节,这比传统的4字节整型伪键占用更多的空间,并且查询的速度更慢。
SQL:UNIQUEIDENTIFIER <=> .Net GUID
开发反模式(GUID) - 伪键洁癖的更多相关文章
- SQL反模式学习笔记22 伪键洁癖,整理数据
目标:整理数据,使不连续的主键Id数据记录变的连续. 反模式:填充断档的数据空缺. 1.不按照顺序分配编号 在插入新行时,通过遍历表,找到的第一个未分配的主键编号分配给新行,来代替原来自动分配的伪主键 ...
- 开发反模式 - SQL注入
一.目标:编写SQL动态查询 SQL常常和程序代码一起使用.我们通常所说的SQL动态查询,是指将程序中的变量和基本SQL语句拼接成一个完整的查询语句. string sql = SELECT * FR ...
- SQL反模式学习笔记5 外键约束【不用钥匙的入口】
目标:简化数据库架构 一些开发人员不推荐使用引用完整性约束,可能不使用外键的原因有一下几点: 1.数据更新有可能和约束冲突: 2.当前的数据库设计如此灵活,以至于不支持引用完整性约束: 3.数据库为外 ...
- SQL反模式学习笔记4 建立主键规范【需要ID】
目标:建立主键规范 反模式:每个数据库中的表都需要一个伪主键Id 在表中,需要引入一个对于表的域模型无意义的新列来存储一个伪值,这一列被用作这张表的主键, 从而通过它来确定表中的一条记录,即便其他的列 ...
- 《SQL 反模式》 学习笔记
第一章 引言 GoF 所著的的<设计模式>,在软件领域引入了"设计模式"(design pattern)的概念. 而后,Andrew Koenig 在 1995 年造了 ...
- SQL反模式学习笔记1 开篇
什么是“反模式” 反模式是一种试图解决问题的方法,但通常会同时引发别的问题. 反模式分类 (1)逻辑数据库设计反模式 在开始编码之前,需要决定数据库中存储什么信息以及最佳的数据组织方式和内在关联方式. ...
- SQL反模式学习笔记9 元数据分裂
目标:支持可扩展性.优化数据库的结构来提升查询的性能以及支持表的平滑扩展. 反模式:克隆表与克隆列 1.将一张很长的表拆分成多张较小的表,使用表中某一个特定的数据字段来给这些拆分出来的表命名. 2.将 ...
- SQL反模式学习笔记19 使用*号,隐式的列
目标:减少输入 反模式:捷径会让你迷失方向 使用通配符和未命名的列能够达到减少输入的目的,但是这个习惯会带来一些危害. 1.破坏代码重构:增加一列后,使用隐式的Insert插入语句报错: 2.查询中使 ...
- SQL反模式学习笔记3 单纯的树
2014-10-11 在树形结构中,实例被称为节点.每个节点都有多个子节点与一个父节点. 最上层的节点叫做根(root)节点,它没有父节点. 最底层的没有子节点的节点叫做叶(leaf). 中间的节点简 ...
随机推荐
- Qt Lite
http://blog.qt.io/blog/2016/08/18/introducing-the-qt-lite-project-qt-for-any-platform-any-thing-any- ...
- cf493B Vasya and Wrestling
B. Vasya and Wrestling time limit per test 2 seconds memory limit per test 256 megabytes input stand ...
- Android菜鸟的成长笔记(28)——Google官方对Andoird 2.x提供的ActionBar支持
在Google官方Android设计指南中(链接:http://www.apkbus.com/design/get-started/ui-overview.html)有一个新特性就是自我标识,也就是宣 ...
- Makefile学习(一)变量
鉴于之前有一些了解,还有自己的学习习惯,我一上来就看Makefile的变量这一章.主要脉络是根据GNU make中文手册. 第六章:Makefile中的变量 6使用变量 定义:变量是一个名字,代表一个 ...
- Gunplot 命令大全
在linux命令提示符下运行gnuplot命令启动,输入quit或q或exit退出. plot命令 gnuplot> plot sin(x) with line linetype 3 linew ...
- git config配置文件 (共有三个配置文件)
设置 git status的颜色. git config --global color.status auto 一.Git已经在你的系统中了,你会做一些事情来客户化你的Git环境.你只需要做这些设置一 ...
- Android字数限制的EditText实现方案研究
在应用开发中,有时需要实现有字数限制的EditText,首先来分析下市面上存在的类似实现方案吧,好有个感性的认识. [方案一:腾讯微博] 每个中文字符算一个字数,每两个英文字符算一个字数,当用户输入内 ...
- 关于java中根据身份证求生日和年龄的问题
/*这个也没什么大的功能,也没什么安全验证,只是对输入的身份证号码的长度进行了验证.其他的功能可以自己添加.*/import java.util.*; import java.util.Scanner ...
- C# viewstate
Viewstate 处理不是form中可以传值的标签 进行传值.可以禁用元素的viewstate 也可以禁用页面的Enableviewstate=”false”;(在配置区域写)内网系统,互联网后台可 ...
- VS2010 rdlc 被除数为0 显示错误号
=Sum(Fields!ROCKNUM.Value/Fields!SEND.Value*100) 当Fields!SEND.Value为0或者空时,显示错误号 修改: =IIF(isnothing(F ...