<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_Richie</title><subtitle type="text">Sometimes at night when I look up at the stars, and see the whole sky just laid out there, don't you think I ain't remembering it all. I still got dreams like anybody else, and ever so often, I am thinking about how things might of been. And then, all of a sudden, I'm forty, fifty, sixty years old, you know?</subtitle><id>http://feed.cnblogs.com/blog/u/21032/rss</id><updated>2011-09-16T11:47:14Z</updated><author><name>riccc</name><uri>http://www.cnblogs.com/RicCC/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/RicCC/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/21032/rss"/><entry><id>http://www.cnblogs.com/RicCC/archive/2010/09/26/1836174.html</id><title type="text">SQL Server用错关联方式</title><summary type="text">SQL Server中不少怪异问题都是由用错关联方式引起的，从2000到2005有所改善，但2005的查询优化引擎还是存在“犯傻”的时候1. 问题1现象：一个存储过程，通过一个服务程序调用，长时间不能结束，数据库服务器显示该存储过程执行到某个语句时一直等待在那，数据库服务器内存充足，CPU消耗几乎没有。把这个存储过程拿出来直接在查询分析器中执行，参数跟程序调用时完全类似，立...</summary><published>2010-09-26T09:51:00Z</published><updated>2010-09-26T09:51:00Z</updated><author><name>riccc</name><uri>http://www.cnblogs.com/RicCC/</uri></author><link rel="alternate" href="http://www.cnblogs.com/RicCC/archive/2010/09/26/1836174.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/RicCC/archive/2010/09/26/1836174.html"/><content type="html">SQL Server中不少怪异问题都是由用错关联方式引起的，从2000到2005有所改善，但2005的查询优化引擎还是存在&amp;#8220;犯傻&amp;#8221;的时候&lt;br /&gt;&lt;br /&gt;1. 问题1&lt;br /&gt;现象：一个存储过程，通过一个服务程序调用，长时间不能结束，数据库服务器显示该存储过程执行到某个语句时一直等待在那，数据库服务器内存充足，CPU消耗几乎没有。把这个存储过程拿出来直接在查询分析器中执行，参数跟程序调用时完全类似，立即结束且结果正确&lt;br /&gt;解决方案：排除了阻塞等原因，因为放在查询分析器中执行时一切正常，从执行计划等方面无法看出任何问题，也排除了磁盘IO等方面的原因，实在想不到其他的了。最后怀疑是SQL Server查询引擎JOIN方式选的不对，强制使用HASH JOIN后，程序调用恢复正常&lt;br /&gt;疑点：一直没有发现程序调用与直接使用查询分析器执行，这2者之间存在哪些差别，会影响到SQL Server查询优化决策&lt;br /&gt;&lt;br /&gt;2. 问题2&lt;br /&gt;现象：一个不算复杂的查询，用到了row_number函数分页，一执行就会导致服务器8个CPU全部100%，很长时间（好几分钟）不能结束。使用临时表实现同样的效果，几秒钟完成&lt;br /&gt;语句1：&lt;br /&gt;&amp;nbsp;&amp;nbsp; SELECT &lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; ROW_NUMBER() OVER(ORDER BY&amp;nbsp; COLUMNNAME1&amp;nbsp; ASC) as FC_ROWNUMBER&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; ,COUNT(1) OVER() AS FC_COUNT&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; ,* FROM ( &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SELECT 产品 as COLUMNNAME1,产品描述 as COLUMNNAME2,入库日期 as COLUMNNAME7,预期数量 as COLUMNNAME8&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ,入库数量 as COLUMNNAME9,行状态 as COLUMNNAME10,供应商 as COLUMNNAME11,供应商名称 as COLUMNNAME12&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; FROM V_收货明细查询&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; where&amp;nbsp;&amp;nbsp; 入库日期 &amp;gt;=&amp;nbsp; '2010-7-1'&lt;br /&gt;&amp;nbsp;&amp;nbsp; ) TT_MAINKEY_TMP &lt;br /&gt;执行计划：&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/error-QEP-query-execution1.JPG" height="251" width="990" /&gt;&lt;br /&gt;&lt;br /&gt;语句2：&lt;br /&gt;SELECT * FROM (&lt;br /&gt;&amp;nbsp;&amp;nbsp; SELECT &lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; ROW_NUMBER() OVER(ORDER BY&amp;nbsp; COLUMNNAME1&amp;nbsp; ASC) as FC_ROWNUMBER&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; ,COUNT(1) OVER() AS FC_COUNT&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; ,* FROM ( &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SELECT 产品 as COLUMNNAME1,产品描述 as COLUMNNAME2,入库日期 as COLUMNNAME7,预期数量 as COLUMNNAME8&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ,入库数量 as COLUMNNAME9,行状态 as COLUMNNAME10,供应商 as COLUMNNAME11,供应商名称 as COLUMNNAME12&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; FROM V_收货明细查询&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; where&amp;nbsp;&amp;nbsp; 入库日期 &amp;gt;=&amp;nbsp; '2010-7-1'&lt;br /&gt;&amp;nbsp;&amp;nbsp; ) TT_MAINKEY_TMP &lt;br /&gt;) TT_RET_TMP &lt;br /&gt;WHERE FC_ROWNUMBER BETWEEN 1 AND 1000 &lt;br /&gt;ORDER BY&amp;nbsp; COLUMNNAME1&amp;nbsp; ASC&lt;br /&gt;执行计划：&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/error-QEP-query-execution2.JPG" height="251" width="746" /&gt;&lt;br /&gt;&lt;br /&gt;仅仅是把SQL作为一个子查询，在外面多包装了一下，整个查询计划就不一样了。排除了统计信息不准确、索引碎片等状况&lt;br /&gt;2个查询计划中对3个表使用的都是聚集索引扫描，基本上就是关联算法不一样&lt;br /&gt;因为用的并行查询，三个表数据都有几十万和一百多万，嵌套循环需要执行几十万次，所以单个查询导致所有CPU都100%。估计高CPU是由于Lazy Spool操作造成的&lt;br /&gt;&lt;br /&gt;解决方案：&lt;br /&gt;强制用HASH JOIN，或者加索引避免SQL Server出错，或者用临时表绕过去&lt;img src="http://www.cnblogs.com/RicCC/aggbug/1836174.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/RicCC/archive/2010/09/26/1836174.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/RicCC/archive/2010/09/15/Transactional-Information-Systems-Part1.html</id><title type="text">事务信息系统-并发控制与恢复的理论, 算法与实践-计算模型, 并发控制部分</title><summary type="text">事务信息系统-并发控制与恢复的理论, 算法与实践页的存储结构图：数据库页的存储布局页是磁盘与主存间传输数据的最小单元，也是内存中进行缓存的单元页头（page header）包含页内空间管理的一些信息，比如空闲空间字节数、最大空闲区域大小等页槽Slot Array的作用：varchar等变长类型字段的更新操作等，可能导致记录在页内移动，如果外部直接以数据记录的物理地址进行引用，记录移动时处理非常复杂...</summary><published>2010-09-15T14:51:00Z</published><updated>2010-09-15T14:51:00Z</updated><author><name>riccc</name><uri>http://www.cnblogs.com/RicCC/</uri></author><link rel="alternate" href="http://www.cnblogs.com/RicCC/archive/2010/09/15/Transactional-Information-Systems-Part1.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/RicCC/archive/2010/09/15/Transactional-Information-Systems-Part1.html"/><content type="html">&lt;a target="_blank" href="http://book.douban.com/subject/1503812/"&gt;事务信息系统-并发控制与恢复的理论, 算法与实践&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong style="font-size: 18pt;"&gt;页的存储结构&lt;/strong&gt;&lt;br style="font-size: 18pt;" /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/tx/database-page-storage-layout.jpg" height="376" width="467" /&gt;&lt;br /&gt;图：数据库页的存储布局页是磁盘与主存间传输数据的最小单元，也是内存中进行缓存的单元&lt;br /&gt;页头（page header）包含页内空间管理的一些信息，比如空闲空间字节数、最大空闲区域大小等&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;页槽Slot Array的作用：&lt;/strong&gt;&lt;br /&gt;varchar等变长类型字段的更新操作等，可能导致记录在页内移动，如果外部直接以数据记录的物理地址进行引用，记录移动时处理非常复杂，所以在中间添加一个隔离层Slot Array。Slot Array中存放页内数据的实际地址，以页号+槽号形成RID，外部均以RID引用数据记录&lt;br /&gt;数据在页内移动时只需要更新Slot Array中的实际地址即可，页间移动可以使用一个Forwarding RID实现，例如上图中的示例&lt;br /&gt;对于包含BLOB等长字段类型的记录，简单技巧可以将列的实际数据存储在其他多个页中，而在记录实际数据位置存储页号列表&lt;br /&gt;&lt;br /&gt;一次磁盘IO可以读取一个或多个连续的页，可以一次读取的固定数目的页称作块（block），在数据库理论中块和页等同对待&lt;br /&gt;数据库系统通常以区间（extent）为单位预先分配磁盘空间（一次预先分配一个或多个区间），区间是多个连续页。注意区间和块的区别&lt;br /&gt;存储层需要保存必要的元数据，例如将页号转换成物理磁盘地址、空闲空间管理等。通常使用区间表（extent table）来完成页号与物理磁盘地址的转换&lt;br /&gt;&lt;br /&gt;&lt;strong style="font-size: 18pt;"&gt;计算模型 Computational Models&lt;/strong&gt;&lt;br style="font-size: 18pt;" /&gt;&lt;strong&gt;页模型page model&lt;/strong&gt;&lt;br /&gt;也称作读写模型read/write model，是一种简单模型。例如事务t使用页模型定义类似如下：t=r(x)w(x)r(y)r(u)w(y)，其中r表示读取数据页，w表示写数据页，对于存储层而言一个事务就是这样一个读写序列或偏序&lt;br /&gt;页模型通过简明优雅的方式抓住并发控制与恢复的实质，可以描述很多系统实现中的重要问题，局限在于仅以低层页的读写操为元素，没有表达数据访问操作的语义&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;对象模型object model&lt;/strong&gt;&lt;br /&gt;对象模型在页模型的基础上考虑高层操作，在对象模型中事务由ADT（abstract data type）操作构成，最终仍归于低层页的读写&lt;br /&gt;下面是一个对象模型示例图：&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/tx/transaction-object-model-example.JPG" height="196" width="459" /&gt;&lt;br /&gt;图：对象模型示例示例场景说明如下：&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; * 事务t1中先执行一个select语句，找出住在城市Austin的人员，然后执行一条insert语句，插入一条住在城市Austin的人员信息&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; * 假设表中只有一个索引，位于城市这个字段，使用的B+ tree结构，索引结构只有2层&lt;br /&gt;&lt;br /&gt;ADT操作以及页的读写说明如下：&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; 1. Search('Austin'): select语句使用城市的索引查找符合Austin的索引项，得到RID列表&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; * r(r): 读取B+ tree索引根节点页&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; * r(l): 读取B+ tree索引叶节点页&lt;br /&gt;&amp;nbsp;&amp;nbsp; 2. Fetch(x), Fetch(y): 根据RID列表加载数据x、y所在的数据页，得到数据记录x、y&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; * r(p), r(q): 分别读取RID x和y所在的数据页p和q&lt;br /&gt;&amp;nbsp;&amp;nbsp; 3. Store(z): 插入记录z&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; * r(f): 读取存储层的元数据页f，其中记录了空闲空间信息&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; * r(p): 从页f上得到页p具有足够空间插入记录z，这里读取这个页p&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; * w(p): 把记录z写入页p，并将页p写回磁盘&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; * r(r), r(l), w(l): 更新城市字段的索引，读取索引根节点页r、叶节点页l，更新叶节点页l并写回磁盘&lt;br /&gt;&lt;br /&gt;对象模型事务t是一棵树，用事务标识符标记根节点，用被调用的操作名称、参数标记非叶节点，用页模型的读写操作标记叶节点&lt;br /&gt;如果将事务的操作序列看成全序，则这个事务只能串行执行；如果将其看作偏序，则其中某些操作可以并行执行&lt;br /&gt;&lt;br /&gt;&lt;strong style="font-size: 18pt;"&gt;经典并发问题&lt;/strong&gt;&lt;br style="font-size: 18pt;" /&gt;脏读dirty-read、不一致读inconsistent-read、幻象读phantom-read参考&lt;a target="_blank" href="http://www.cnblogs.com/RicCC/archive/2010/03/05/transaction-lock-isolation-level.html"&gt;Transaction, Lock, Isolation Level&lt;/a&gt;&lt;br /&gt;更新丢失lost-update：&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/tx/lost-update-problem.JPG" height="196" width="421" /&gt;&lt;br /&gt;图：丢失更新问题&lt;br /&gt;&lt;br /&gt;&lt;strong style="font-size: 18pt;"&gt;页模型上的并发控制 - 调度协议&lt;/strong&gt;&lt;br style="font-size: 18pt;" /&gt;页模型的可串行性理论有终态可串行性、视图可串行性、冲突可串行性等，由于判定终态可串行性和视图可串行性的复杂度太高，因此商业数据库基本都采用冲突可串行性CSR类进行判定&lt;br /&gt;概念：&lt;br /&gt;历史history：指一个完整、已经结束的事务，即事务要么使用commit提交了，要么使用abort终止了&lt;br /&gt;调度schedule：指未完成的事务，即历史的一个前缀&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/tx/transaction-scheduler.JPG" height="274" width="444" /&gt;&lt;br /&gt;图：Transaction Scheduler图：事物调度器 Transaction Scheduler&lt;br /&gt;client 1、client 2等代表不同事物的操作序列&lt;br /&gt;事务管理器TM主要任务是事物登记，管理trans、commit、abort、active列表，维护ready-to-execute列表等&lt;br /&gt;调度器从TM接收输入调度，将其转化为可串行化的输出调度&lt;br /&gt;调度器分为乐观的、悲观的&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;死锁处理&lt;/strong&gt;&lt;br /&gt;一般基于等待图waits-for graph WFG概念，WFG中存在环路时即发生死锁&lt;br /&gt;死锁检测：持续检测continuous detection、周期检测periodic detection&lt;br /&gt;死锁处理方法一：允许发生死锁，从死锁中选出牺牲者消除WFG环路；处理方法二：死锁预防，即不允许死锁情况发生&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;两阶段封锁协议 - two-phase locking protocol - 2PL&lt;/strong&gt;&lt;br /&gt;对每个事物，加锁阶段严格区别于紧接着的释放阶段，该封锁协议就是两阶段的&lt;br /&gt;即可以明确的将事务分成前后两个部分，在前面部分只存在加锁，不存在锁释放，而在后面部分则只存在锁释放操作，没有加锁操作。商业数据库考虑性能问题不会严格按照2PL协议实现。SQL92不同的隔离级别本身就是性能与可串行性之间的一个取舍平衡，另外页模型并没有考虑到语义方面，商业数据库部分结合语义方面之后也能对封锁协议进行改造优化以换取性能&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/tx/transaction-2pl.JPG" height="131" width="262" /&gt;&lt;br /&gt;图：2PL下锁增长和缩减阶段示意图图：2PL下锁增长和缩减阶段示意图&lt;br /&gt;&lt;br /&gt;2PL协议具有C2PL、S2PL、SS2PL几种变体&lt;br /&gt;下面是一个2PL调度器的调度示例：&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/tx/transaction-scheduler-2pl-example.JPG" height="213" width="464" /&gt;&lt;br /&gt;图：调度示例图：2PL调度器调度示例&lt;br /&gt;顶部的s是输入，底部3行是经过2PL调度器的一种可行的输出&lt;br /&gt;下表1、2、3等表示不同的事物t1、t2、t3等，wl表示加写锁，wu表示释放写锁，rl表示加读锁，ru表示释放读锁，c表示事物结束（commit）&lt;br /&gt;中间部分锁的持有时序图中，虚线部分表示锁冲突时的等待时间&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;保守2PL - Conservative 2PL - C2PL&lt;/strong&gt;&lt;br /&gt;在事物开始时对所有需要访问的数据获取锁。这个协议只能在有限的应用场景下使用，他不存在死锁问题，因为事物要么等待不能开始，要么就已经得到了全部所需的锁了&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/tx/transaction-c2pl.JPG" height="132" width="268" /&gt;&lt;br /&gt;图：C2PL下锁增长和缩减阶段示意图图：C2PL下锁增长和缩减阶段示意图&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;严格2PL - Strict 2PL - S2PL&lt;/strong&gt;&lt;br /&gt;事物一直持有已经获得的所有写锁，直到事物终止&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/tx/transaction-s2pl.JPG" height="132" width="264" /&gt;&lt;br /&gt;图：S2PL下锁增长和缩减阶段示意图图：S2PL下锁增长和缩减阶段示意图（假设事物中的锁都是写锁）&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;强2PL - Strong 2PL - SS2PL&lt;/strong&gt;&lt;br /&gt;事物获得的所有锁（包括读锁和写锁）被一直保持直到事物终止。这种情况下锁的增长和缩减阶段与S2PL相同，不过不局限于写锁&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;有序共享2PL - Ordered Sharing 2PL - O2PL&lt;/strong&gt;&lt;br /&gt;在2PL中，如果对同一个数据项申请的锁，与这个数据项上面已经存在的锁不相容时，就只能等待&lt;br /&gt;有序共享相容性规则：同一个数据项上的两个锁无论是否冲突，只要锁操作与相应的数据操作均以相同的顺序执行就可以被不同事物同时持有。这个规则以固定的顺序对数据项进行操作为前提，从而放宽了锁相容性规则，理论上证明是可行的，但他必须强制数据访问的顺序，需要额外的数据结构和运行时代价，实际中比较少采用&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;利他锁 - Altruistic Locking - AL&lt;/strong&gt;&lt;br /&gt;是2PL的一种扩展协议。某些事物时间可能很长，持有大量的锁，这样可能阻塞大量其他短事物。如果短事物访问的仅仅是长事物已经处理过的数据项的子集，则长事物将这部分数据项捐赠给其他事物访问&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;非两阶段封锁协议&lt;/strong&gt;&lt;br /&gt;有只写封锁树 write-only tree locking WTL、读写封锁树read/write tree locking RWTL等，他们只能在对数据项的访问遵从特定的顺序的情况下使用，比如对数据项的访问呈树状方式&lt;br /&gt;WTL在封锁规则的基础上添加了两条附加规则：只有在持有父项数据写锁的情况下，才能获取子项数据的写锁；事物对释放某个数据项的写锁之后，不能在获得该数据项的写锁。这确保了数据更新处理将沿着树的某一路径从根节点向叶节点进行，锁的范围可以限制在某个子树范围内。锁的申请和释放并不是两阶段的，沿着数的路径向子树进行时，父项的锁可以释放，即锁的申请和释放可以交替进行&lt;br /&gt;WTL协议是无死锁的，对RWTL协议规则稍作修改可以导出DAG封锁协议DAG locking protocol&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;时间戳排序协议 - timestamp ordering protocol - TO&lt;/strong&gt;&lt;br /&gt;不使用封锁，基本规则是对不同事物冲突的操作，严格按照事物开始时间的先后关系进行调度&lt;br /&gt;在封锁协议中通过锁机制检测冲突，在TO中也需要有额外的信息用于检测冲突。例如Ti在Tj之前开始，调度器先对Tj输出了一个调度qj(x)，但后来 Ti发送过来一个pi(x)的操作，与qj(x)冲突（即按照TO规则，pi(x)必须在qj(x)之前执行，但在pi(x)之前qj(x)已经被调度输出了），所以调度器需要记录信息以检测这种冲突并作出相应处理（例如阻塞Ti，等待Tj结束后再开始）&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;SGT协议 - Serialization Graph Tester - 可串行化图检测器&lt;/strong&gt;&lt;br /&gt;维护一张SGT图，图中并发的每个事物拥有一个节点，事物Ti的操作与Tj冲突，如果Tj中发生冲突的操作已经输出了，则由Tj向Ti添加一条有向边，Ti进入等待状态。如果事物Ti的某个操作导致SGT图中存在环路，则输出是不可串行化的，事物Ti需要取消&lt;br /&gt;实际中SGT协议需要维护的额外数据量以及运算量都比较大，对于调度器而言无法接收，所以很少采用&lt;br /&gt;&lt;br /&gt;&lt;strong style="font-size: 18pt;"&gt;对象模型上的并发控制，搜索结构上的并发控制&lt;/strong&gt;&lt;br style="font-size: 18pt;" /&gt;......&lt;br /&gt;&lt;br /&gt;&lt;strong style="font-size: 18pt;"&gt;多版本并发控制 - multiversion concurrency control&lt;/strong&gt;&lt;br style="font-size: 18pt;" /&gt;单版本时数据库中的每个数据项只有一个副本，而多版本时则会为数据项同时维护多个版本，而多版本对于client是透明的，对client而言数据库仍然只维护了数据项的一个副本。通过对并发控制算法的扩展调整，多版本同样可以达到可串行性目标，他仅仅是并发控制的另一种处理方式。他的优点是可以降低封锁协议中锁的使用，极大的提高并发处理性能，并给数据恢复等方面带来好处&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;多版本时间戳排序协议 - multiversion timestamp ordering protocol - MVTO&lt;/strong&gt;&lt;br /&gt;本质上类似FIFO方式处理并发操作。每个事物按照事物开始时的时间戳排序，基于这个顺序处理调度和冲突&lt;br /&gt;下面对的规则描述中，Ti表示第i个事物；ts(Ti)表示第i个事物的时间戳；Ri(X)表示Ti读取数据项X；Xk则表示数据项X的某一个版本，他是由事物Tk写入的；ts(Xk)表示数据项的Xk这个版本的时间戳，他就是事物Tk的时间戳，即ts(Xk)=ts(Tk)。下面是MVTO规则：&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; 1. Ri(X)将被转化为Ri(Xk)，即需要明确读取数据项X的哪一个版本，其中Xk应该为ts(Xk)&amp;lt;ts(Ti)的一个最新版本。另外Xk可能是已提交的版本，也可能是未提交的版本&lt;br /&gt;&amp;nbsp;&amp;nbsp; 2. 处理Wi(X)时，如果已经存在一个Rj(Xk)操作，并且时间戳关系为ts(Xk)&amp;lt;ts(Ti)&amp;lt;ts(Tj)，则Wi(X)被拒绝，Ti将被取消，因为这样存在冲突，将造成不可串行化的结果。否则，Wi(X)被转化为Wi(Xi)并执行，即为数据项X生成一个新的版本Xi&lt;br /&gt;&amp;nbsp;&amp;nbsp; 3. 可选规则：延迟提交。这是在不允许脏读的情况下用来避免产生脏读的一个机制。如果事物Ti读取了Tj写入的某个数据项，即存在Ri(Xj)操作，则事物Ti的提交操作Ci需要被推迟到事物Tj成功提交之后再执行。如果事物Tj失败则事物Ti也失败（或重做）&lt;br /&gt;&lt;br /&gt;下面是MVTO协议下的一个执行示例，可以使用上面的规则进行解释：&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/tx/transaction-mvto-example.JPG" /&gt;&lt;br /&gt;图：MVTO协议下的执行示例&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; * 事物t3中因为存在r3(x2)操作，即读取了x2这个未提交的版本（按照规则1，他应该读取x2的），所以他的提交被延迟（虚线表示等待），在t2提交之后再提交&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; * t4被终止是因为规则2的作用，因为t5中存在r5(y2)这个操作，如果让w4(y4)成功，则事物t5可能出现不一致读的情况，不是一个可串行化的调度。图来自原书，图中应该有个错误，r5(y2)不可能出现在w2(y2)前面的，他应该位于w2(y2)与w4(y4)之间才对&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; * 最后看一下t1，在读取y的时候，根据MVTO的规则1，应该读取y0这个版本。这样在没有加锁的情况下实现了事物t1的一致性读，但他并没有利用锁阻塞t2、t4（两阶段封锁协议的情况下他们的写操作与t1的读锁冲突），而是让t2、t4并行执行。根据MVTO规则，t1不能有写x、y的操作，否则按照规则2应该取消t1。这样从理论上看存储层还是可以保证x、y的可串行性结果的，但存在一个疑问是：&lt;strong&gt;如果t1有其他写操作，比如 w1(u1)，而u1是基于x、y的运算而来，即u1=f0(u)f1(x)f2(y)，如何确保数据项u的可串行性结果呢？还有对外部而言t1实现了对 x、y的一致性读，但w2(y2)成功了，外部基于x、y得来的计算结果可能就是一个不正确的值，如何确保一致性？&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;另外还有多版本两阶段封锁协议 - multiversion 2PL locking protocol - MV2PL、只读多版本协议 - read-only multiversion protocol - ROMV等&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;暂态版本化 - Transient Versioning&lt;/strong&gt;&lt;br /&gt;暂态版本化的做法是将数据项的最新版本放在数据记录位置上，数据项以前的旧版本都放在版本池version pool中，版本池可以驻留内存或者磁盘。这样当访问最新版本数据时没有性能损失，版本池也方便对旧版本的垃圾回收。有些系统中把版本池跟用于恢复的日志项合并在一起。版本池也叫做回滚段rollback segment&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/tx/data-structure-of-transient-versioning.JPG" height="233" width="352" /&gt;&lt;br /&gt;图：暂态版本化的存储组织图：暂态版本化的存储组织&lt;br /&gt;数据项的每个版本包括两个额外的字段，一个是创建时间戳，另一个是指向前一版本的指针&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; * 对于新增的数据项，还没有旧版本，因此在当前版本中指针为空，例如图中的1135&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; * 删除的数据仍然保留在当前版本位置上，但会打上删除标记，例如图中的1141&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; * 同一个数据项的各个版本组成一个链表&lt;br /&gt;&lt;br /&gt;另一种方法是在数据项的当前版本中维护一个小的版本选择表，其中包含每个版本的时间戳以及一个指向该版本位置的指针&lt;br /&gt;如果一个数据项的旧版本再也不会被当前活动的事务使用到，则这些旧版本就成为垃圾，可以被回收掉&lt;br /&gt;&lt;br /&gt;&lt;strong style="font-size: 18pt;"&gt;关系数据库的并发控制&lt;/strong&gt;&lt;br style="font-size: 18pt;" /&gt;&lt;strong&gt;面向谓词的并发控制 - Predicate-Oriented Concurrency Control&lt;/strong&gt;&lt;br /&gt;封锁协议是针对页、数据项加锁，而面向谓词的并发控制是针对操作加锁，更具体的是针对操作的谓词加锁。例如：&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; select name from persons where age&amp;gt;30&lt;br /&gt;则将age&amp;gt;30与锁关联&lt;br /&gt;面向谓词的并发控制是比较早提出来的一种想法，后来也经过了不少研究，他的问题在于检测两个谓词是否兼容是一个NP完全问题，成本太高，但在特定场景下，例如B+树上的并发控制，具有实际意义&lt;br /&gt;&lt;br /&gt;&lt;strong style="font-size: 18pt;"&gt;实现和实用性问题&lt;/strong&gt;&lt;br style="font-size: 18pt;" /&gt;通用的锁管理器数据结构&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/tx/data-structure-of-lock-manager.JPG" height="382" width="614" /&gt;&lt;br /&gt;图：锁管理器的数据结构&lt;br /&gt;锁管理器需要达成的目标：&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; 1. 请求锁时可以检验冲突&lt;br /&gt;&amp;nbsp;&amp;nbsp; 2. 释放锁时，需要将资源授予被该锁阻塞的其他锁&lt;br /&gt;&amp;nbsp;&amp;nbsp; 3. 事务终止时释放该事务的所有锁&lt;br /&gt;&lt;br /&gt;锁管理器的数据结构常驻内存，由resource ID索引的哈希表存放已经加锁以及需要加锁的资源ID&lt;br /&gt;每个哈希表项指向一个资源控制块RCB，RCB中的hash chain用于解决hash冲突&lt;br /&gt;对于共享锁，多个锁可以同时被同一资源持有，多个锁请求（例如冲突的写锁）可能正在等待被授予该资源上，这样在同一个资源上将形成一个已持有的共享锁列表以及等待被授予的排他锁与共享锁队列，因此在RCB上会指向一个锁控制块LCB的链接表，即上图中的FirstInQueue, NextInQueue链表&lt;br /&gt;为了达成第3点，为每个活动事务维护一个事务控制块TCB，同样使用链表将该事务的所有锁链接起来，即上图中的LCB chain构成的链表&lt;br /&gt;&lt;br /&gt;锁的数据结构将是数据库中访问最频繁的地方之一，因此需要控制这个内存数据结构的大小来避免性能问题，所以一般数据库中存在锁粒度升级的处理方式。如果一个事务已经持有了大量细粒度的行锁，数据库可能会将锁粒度升级为页锁或者表锁，以减小锁管理器的内存空间&lt;br /&gt;使用了不同粒度的锁，就存在不同粒度之间相容性的判断问题，所以引入了意向锁，参考&lt;a target="_blank" href="http://www.cnblogs.com/RicCC/archive/2010/09/15/Database-System-An-Application-Oriented-Approach.html"&gt;数据库系统 - 面向应用的方法&lt;/a&gt;&lt;img src="http://www.cnblogs.com/RicCC/aggbug/1827449.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/RicCC/archive/2010/09/15/Transactional-Information-Systems-Part1.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/RicCC/archive/2010/09/15/Database-System-An-Application-Oriented-Approach.html</id><title type="text">数据库系统 - 面向应用的方法</title><summary type="text">数据库系统-面向应用的方法一些概念关系、元组、属性在关系数据库理论中，关系 (relation)对应于数据库技术的表 (table)，元组 (tuple)对应于行 (row)，属性 (attribute)对应于列 (column)元组的元 (arity)为属性数量，即列的数量，一元unitary，二元binary，三元ternary等关系的势 (cardinality)为关系中的元组数量，即行数P...</summary><published>2010-09-15T14:25:00Z</published><updated>2010-09-15T14:25:00Z</updated><author><name>riccc</name><uri>http://www.cnblogs.com/RicCC/</uri></author><link rel="alternate" href="http://www.cnblogs.com/RicCC/archive/2010/09/15/Database-System-An-Application-Oriented-Approach.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/RicCC/archive/2010/09/15/Database-System-An-Application-Oriented-Approach.html"/><content type="html">&lt;a target="_blank" href="http://book.douban.com/subject/1914952/"&gt;数据库系统-面向应用的方法&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 18pt;"&gt;&lt;/span&gt;&lt;strong style="font-size: 18pt;"&gt;一些概念&lt;/strong&gt;&lt;br style="font-size: 18pt;" /&gt;&lt;strong&gt;关系、元组、属性&lt;/strong&gt;&lt;br /&gt;在关系数据库理论中，&lt;strong&gt;关系 (relation)&lt;/strong&gt;对应于数据库技术的表 (table)，&lt;strong&gt;元组 (tuple)&lt;/strong&gt;对应于行 (row)，&lt;strong&gt;属性 (attribute)&lt;/strong&gt;对应于列 (column)&lt;br /&gt;元组的&lt;strong&gt;元 (arity)&lt;/strong&gt;为属性数量，即列的数量，一元unitary，二元binary，三元ternary等&lt;br /&gt;关系的&lt;strong&gt;势 (cardinality)&lt;/strong&gt;为关系中的元组数量，即行数&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Projection operator 投影运算&lt;/strong&gt;&lt;br /&gt;即选取仅选取部分列的查询&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Materialized view 物化视图&lt;/strong&gt;&lt;br /&gt;即被高速缓存的视图&lt;br /&gt;&lt;br /&gt;&lt;strong style="font-size: 18pt;"&gt;RAID&lt;/strong&gt;&lt;br /&gt;Redundant Array of Independent Disks，廉价磁盘冗余阵列。利用拆分（striping）提高性能，使用冗余提高可靠性。参考RAID on wikipedia&lt;br /&gt;&lt;strong&gt;RAID0&lt;/strong&gt;&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/dis/RAID0.png" height="185" width="120" /&gt;&lt;br /&gt;RAID0块级拆分，没有冗余。拆分的文件支持并发存取，但任何一块磁盘损坏将导致所有文件损坏&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;RAID1&lt;/strong&gt;&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/dis/RAID1.png" height="185" width="120" /&gt;&lt;br /&gt;RAID1仅做冗余，没有拆分。支持并发读取，提高了读取性能，写入时需要同时写入多块磁盘&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;RAID2&lt;/strong&gt;&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/dis/RAID2.png" height="200" width="400" /&gt;&lt;br /&gt;RAID2字节级拆分（文件相邻的字节均被拆分存储到不同磁盘中），有一块或多块奇偶校验盘（图中的Disk 4, 5, 6）用于容错&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;RAID3&lt;/strong&gt;&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/dis/RAID3.png" height="222" width="300" /&gt;&lt;br /&gt;RAID3字节级拆分，有一块独立的奇偶校验盘（图中的Disk 3）&lt;br /&gt;&lt;strong&gt;&lt;br /&gt;RAID4&lt;/strong&gt;&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/dis/RAID4.png" height="222" width="300" /&gt;&lt;br /&gt;RAID4块级拆分，有一块独立的奇偶校验盘。任何一块磁盘损坏不会造成数据丢失，2块盘损坏时将丢失数据&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;RAID5&lt;/strong&gt;&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/dis/RAID5.png" /&gt;&lt;br /&gt;RAID5块级拆分，具备奇偶校验，但没有独立的奇偶盘，奇偶校验与文件数据一起被拆分在多个盘中。任何一块磁盘损坏不会造成数据丢失，2块盘损坏时将丢失数据&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;RAID6&lt;/strong&gt;&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/dis/RAID6.png" height="200" width="340" /&gt;&lt;br /&gt;RAID6块级拆分，有2块奇偶盘，最多在2块磁盘损坏时不会造成数据丢失&lt;br /&gt;&lt;br /&gt;&lt;strong style="font-size: 18pt;"&gt;存储&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;堆文件 heap file&lt;/strong&gt;：记录无序，仅在末尾添加，删除记录时不释放空间，不适合查询&lt;br /&gt;&lt;strong&gt;顺序文件 sorted file&lt;/strong&gt;：按某些列的顺序存放，可运用二分查找等优化算法&lt;br /&gt;&lt;strong&gt;填充因子 fill factor&lt;/strong&gt;：每页预留空间供插入操作，预留空间满了以后使用溢出链overflow chain支持插入操作&lt;br /&gt;&lt;br /&gt;&lt;strong style="font-size: 18pt;"&gt;索引&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;集成索引 integrated index&lt;/strong&gt;：索引条目跟数据记录集成在一起&lt;br /&gt;&lt;strong&gt;聚集索引 clustered index&lt;/strong&gt;：对于有序索引（B+ tree等），如果索引条目与数据记录都是按照相同的search key排序的，则为聚集索引，集成索引是一种聚集索引；对于散列（hash）索引，如果散列索引条目就是数据记录则为聚集的，此时hash bucket本身就是数据文件的存储结构，数据文件就是hash bucket的序列&lt;br /&gt;聚集索引通常又称为main index，非聚集索引又称为secondary index&lt;br /&gt;&lt;strong&gt;稠密索引 dense idnex&lt;/strong&gt;：索引条目与数据记录一一对应&lt;br /&gt;&lt;strong&gt;稀疏索引 sparse index&lt;/strong&gt;：索引条目与数据页一一对应（与数据记录为一对多关系）&lt;br /&gt;&lt;br /&gt;&lt;strong style="font-size: 12pt;"&gt;ISAM: Indexed Sequential Access Method&lt;/strong&gt;&lt;br style="font-size: 12pt;" /&gt;ISAM结构示意图：&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/dis/ISAM-structure.jpg" height="211" width="600" /&gt;&lt;br /&gt;ISAM结构示意图非页节点称为分隔符级，一个分隔符节点示意图如下：&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/dis/ISAM-separator-node.jpg" height="54" width="300" /&gt;&lt;br /&gt;ISAM分隔符节点示意图其中Pn为指向下一级节点的指针，Kn为搜索码的值。Pi-1指向的K值&amp;lt;Ki&amp;lt;=Pi指向的K值&lt;br /&gt;&lt;br /&gt;ISAM的分隔符级节点一旦创建便不再更改，因此ISAM被称为静态索引。叶子页中的条目被除时其空间不会释放，相关的分隔符级也不会更新，即可能出现分隔符级页中出现的某些search key在叶子节点上没有对应条目。插入时叶子页使用fill factor和overflow chain&lt;br /&gt;ISAM对相对静态的表有效，动态表通常不用ISAM索引&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;B+ Tree&lt;/strong&gt;&lt;br /&gt;B+ tree结构示意图：&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/dis/B-tree-structure.jpg" height="173" width="658" /&gt;&lt;br /&gt;B+ tree结构示意图根节点到达任何一个叶子页的级数是一样的。叶子页添加了兄弟指针，方便range search，支持范围搜索、等值搜索、部分码搜索方式&lt;br /&gt;叶子页至少包含(n-1)/2个值，最多包含n-1个值。维护B+ Tree结构（插入、删除操作等）算法复杂&lt;br /&gt;节点与ISAM类似：&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/dis/B-tree-separator-node.jpg" height="88" width="400" /&gt;&lt;br /&gt;B+ tree节点示意图&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Hash索引&lt;/strong&gt;&lt;br /&gt;只能等值搜索，这种情况下比B+ tree更有效&lt;br /&gt;也需要使用overflow chain&lt;br /&gt;有静态散列算法、动态散列算法（包括可扩展散列、线性散列）&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Bit map 位图索引&lt;/strong&gt;&lt;br /&gt;位图索引一般用于低势属性（取值范围很小的属性）&lt;br /&gt;为每一个取值建立一个位图向量，每一位对应于数据的某一行。例如有PERSON表SEX列，取值范围为(MALE, FEMALE)，数据4000行，则将建立2个位图向量V(male)、V(female)，每个向量有4000位。如果V(male)i=1则表示第i 行记录SEX列取值MALE&lt;br /&gt;现在假如有这样一个查询：SEX='MALE' AND SMOKE='YES'，如果这2个列都有位图索引，则可以用V(sex-male) &amp;amp; V(smoker-yes)这个运算（位AND运算）得到满足条件的行&lt;br /&gt;位图索引存在空间浪费，但特定情况下效率很高。另外位图索引的维护成本比较高，因此不适合频繁插入、更新的表&lt;br /&gt;&lt;br /&gt;&lt;strong style="font-size: 18pt;"&gt;查询优化器&lt;/strong&gt;&lt;br style="font-size: 18pt;" /&gt;&lt;strong&gt;Rule based optimizer&lt;/strong&gt;：基于既定的规则优化查询计划&lt;br /&gt;&lt;strong&gt;Cost-based optimizer&lt;/strong&gt;：在RBO的基础上增加统计信息，结合评估成本与既定规则优化查询计划&lt;br /&gt;&lt;br /&gt;&lt;strong style="font-size: 18pt;"&gt;事物&lt;/strong&gt;&lt;br style="font-size: 18pt;" /&gt;有关事务的部分内容可以参考&lt;a href="http://www.cnblogs.com/RicCC/archive/2010/03/05/transaction-lock-isolation-level.html"&gt;事物、锁、隔离等级&lt;/a&gt;&lt;br /&gt;在数据库理论中检验事物正确性以完全串行化执行结果为基准，考虑并发处理后采用两阶段封锁协议(two-phase locking protocol, 2PL)，访问资源（读、写）时先申请锁&lt;br /&gt;考虑并发性能问题，锁分成不同的粒度，典型的为表级锁、页级锁、行级锁&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;为什么需要意向锁？&lt;/strong&gt;&lt;br /&gt;因为有不同粒度的锁存在，为了优化锁冲突的判断处理而设计出意向锁&lt;br /&gt;比如事物t1更新了某条记录，对这条记录加了写锁。而事物t2需要读取这个表的所有记录，需要对表加读锁。事物控制器如何确定这2个事物的加锁请求是否冲突？&lt;br /&gt;有了意向锁之后，事物t1在更新记录时，对这个表加意向排他锁IX（如果有页锁，则对数据记录所在页也加IX锁）；事物t2申请这个表上的共享锁S时，就只需要检测表（以及页）上面已存在的锁是否与S锁冲突，而IX与S是冲突的，所以t2只有等待。这样避免了锁冲突判断时需要理解并处理加锁对象的类型以及之间的关系&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;意向锁类型&lt;/strong&gt;&lt;br /&gt;IS, Intention Shared, 意向共享锁：对行取读锁S时，则必须获取表的IS锁&lt;br /&gt;IX, Intention Exclusive, 意向排他锁：要更新某一行，则必须先获取该表的IX锁&lt;br /&gt;SIX, Shared Intention Exclusive, 共享意向排他锁：例如要更新某些行，但必须执行表扫描才能确定具体需要更新的行，则加SIX锁，它是共享锁与意向排他锁的结合&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;先写式日志 Write-ahead log&lt;/strong&gt;&lt;br /&gt;更新记录 update record：用于确保事物的原子性、持久性机制，事物终止（rollback）时可以根据更新记录回滚。更新日志中包含before image，即记录被更新之前的状态，因此可以用它来撤销更改。因此更新记录也被称为undo record&lt;br /&gt;日志示意图：&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/Database/dis/database-log-example.JPG" height="53" width="556" /&gt;&lt;br /&gt;数据库日志示意图 Ui：事物Ti的更新记录 update record&lt;br /&gt;Bi：事物Ti的开始记录 begin record&lt;br /&gt;Ci：事物Ti的开始记录 commit record&lt;br /&gt;Ai：事物Ti的开始记录 abort record&lt;br /&gt;CK：Check Point&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; 1. 终止事物时，在日志中反向扫描处理到该事物的begin record就完成了&lt;br /&gt;&amp;nbsp;&amp;nbsp; 2. 系统崩溃时需要将当时所有活动事物全部回滚（系统崩溃时内存信息已经丢失，只能根据日志操作），所以用commit record、abort record标识那些已经结束了的事物&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 另外，除非反向扫描完整个日志文件，否则无法确定崩溃时哪些事物为活动事物，因此在日志中定期记录check point record，用来记录检查点时刻系统中所有活动的事物id。这样崩溃恢复时只需要反向扫描到任何一个check point record就有方法确定扫描的终止条件&lt;br /&gt;&lt;br /&gt;更新数据时，先更新数据文件还是先写日志？&lt;br /&gt;如果先更新数据文件，在日志文件还没有写入时发生崩溃，则这个数据可能无法恢复；如果先写日志，在数据未更新时发生崩溃，则恢复处理不会造成数据错误。因此叫做write-ahead log&lt;br /&gt;除了before image外，日志可能还包括after image，即记录更新之后的状态，用于重做事物，因此也叫redo record。例如某时刻数据库损坏，则可以用之前的某个备份加上redo log恢复到崩溃之前的某个状态，将损失降到最低&lt;img src="http://www.cnblogs.com/RicCC/aggbug/1827433.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/RicCC/archive/2010/09/15/Database-System-An-Application-Oriented-Approach.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/RicCC/archive/2010/09/13/Data-Modeling-Technologies.html</id><title type="text">Data Modeling Technologies - ER, IE, Barker, IDEF1X, EXPRES-G, ORM</title><summary type="text">各种数据建模技术，包括ER, IE, Barker, IDEF1X, EXPRES-G, ORM</summary><published>2010-09-13T02:10:00Z</published><updated>2010-09-13T02:10:00Z</updated><author><name>riccc</name><uri>http://www.cnblogs.com/RicCC/</uri></author><link rel="alternate" href="http://www.cnblogs.com/RicCC/archive/2010/09/13/Data-Modeling-Technologies.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/RicCC/archive/2010/09/13/Data-Modeling-Technologies.html"/><content type="html">&lt;strong style="font-size: 18pt;"&gt;Entity Relationship Model - ER模型 - 实体关系模型&lt;/strong&gt;&lt;br style="font-size: 18pt;" /&gt;1976年Peter Chen首次提出了Entity Relationship Modeling（实体关系建模）概念，并发明了陈氏表示法Peter Chen's Notation，因此ER模型也可以叫做Chen's Model（陈氏模型）。下面是一个ER模型（ERD - ER diagram - Entity Relationship diagram）示例：&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/design/ER/ERD-ER-Model.jpg" height="360" width="596" /&gt;&lt;br /&gt;图：ER模型 - Peter Chen's Notation图：ER模型 - Peter Chen's Model，实际上这是一个EER - Enhanced Entity-Relationship Model，扩展ER模型&lt;br /&gt;&lt;strong&gt;Entity 实体&lt;/strong&gt;：使用方框表示&lt;br /&gt;&lt;strong&gt;Attribute 属性&lt;/strong&gt;：使用圆或椭圆表示。实体和实体关系都可以拥有属性，例如图中的Order-Line关系拥有3个属性&lt;br /&gt;&lt;strong&gt;&lt;br /&gt;Relationship 关联关系&lt;/strong&gt;：使用菱形表示，菱形中写上关联关系的名字&lt;br /&gt;ER模型中关联关系也可以拥有属性，在多对多关联关系中不需要使用额外中间关联实体来表示，关联关系本身就可以作为这个中间实体。另外ER模型的关联关系不限于2个实体之间，可以在多个实体间使用一个关联关系&lt;br /&gt;&lt;strong&gt;&lt;br /&gt;Unique Identifier 唯一标识&lt;/strong&gt;&lt;br /&gt;陈氏表示法没有很好的解决唯一标识问题，仅使用一种简单的标记方法，下图表示Party的ID作为Purchase Order唯一标识一员的情况，关联关系名称改为E，朝依赖实体方使用一个箭头，依赖实体使用一个额外的方框括起来&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/design/ER/ERD-peter-chen-unique-id.jpg" height="40" width="345" /&gt;&lt;br /&gt;图：ER模型中唯一标识的表示方法图：ER模型中唯一标识的表示方法&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Sub-type 子类型&lt;/strong&gt;&lt;br /&gt;最初的陈氏表示法中不包含子类型概念，后来Robert Brown和Mat Flavin添加了子类型表示法，这种ER模型称为扩展ER模型。上图ER模型中有一个子类型例子，超类Party派生出子类Organization和 Person&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Constraints between relationships 关联关系的约束&lt;/strong&gt;&lt;br /&gt;最初的陈氏表示法中关联关系的每一端只使用一个数字表示，比如一对多的关联关系，在一端使用1，另一端实体上使用n表示，这对关联关系约束不充分。上图的 ER模型在关联关系每一端使用2个数字表示，这与Crow's Foot表示法以及UML中的optionality（可选项）、cardinality（关联基数）有些类似又有较大的区别，详细说明如下：&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #808080;"&gt;上图中一个Purchase Order必须关联一个Party，必须关联一个或多个Order Line，每个Order Line要么是一个Product要么是一个Service&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #808080;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Purchase Order右边的(1,)1表示一个Purchase Order有且必须有一个Party&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #808080;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Party左边的(0,)n表示一个Party可以拥有多个Purchase Order，也可以没有&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #808080;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Purchase Order左边的(1,)n表示Purchase Order必须有一个或多个Order Line&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #808080;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Order Line右边的(1,)1表示每个Order Lien必须属于一个Purchase Order&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #808080;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Order Line下面的(1,)1和菱形符号一起表示每个Order Line要么是一个Product要么是一个Service&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #808080;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Product和Service上面的(0,)n表示Product和Service可以属于0个或多个Order Line&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #808080;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Event和Event Category的关联关系稍特殊（实际中这种 n:1 的关系不多见），他不是一个普通的多对一关系。Event可以关联一个Event Category也可以不关联，而Event Category则必须关联一个或多个Event&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Order-Line和Product、Service之间是一个exclusive or约束（异或、互斥约束，disjunctive mandatory约束）关系，使用超类和子类一样的表示法来表示。因为exclusive or的语义本身已经已经表明Order Line必须是Product或者Service其中之一，因此上图中Order Line右边和下面的(1,)1是多余的&lt;br /&gt;&lt;br /&gt;&lt;strong style="font-size: 18pt;"&gt;EER - Enhanced Entity-Relationship Model 扩展ER模型&lt;/strong&gt;&lt;br style="font-size: 18pt;" /&gt;上面已经有些内容不属于最初的陈氏表示法，是后来其他人扩展的。陈氏表示法出现的早也存在一些不足，因此存在一些扩展以弥补缺陷，不同文档中使用的ER图也不尽相同，例如下图是wiki上的一个示例ER模型&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/design/ER/ERD-ER-in-wiki.jpg" height="579" width="650" /&gt;&lt;br /&gt;图：Wiki上的ER模型示例图：Wiki上的ER模型示例&lt;br /&gt;属性带下划线表示主键属性；关联关系连接线为两条线的表示"最少一个，或多个"（用于n的一端）；实体和关联关系使用两个框的，可能是上面讲到的唯一标识表示法，也可能是"最少一个，或多个"表示法的一部分（这一点有待确认）。还有一些，例如属性与实体间用两条线连接的表示该属性为多值属性（上图中Region实体的Foliage属性）。图中的部分解释如下：&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #808080;"&gt; 1 Account has n(at least one) Character, Account的AcctName属性将成为Has的唯一标识的一员;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #808080;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1 Region contains n(at least one) Character, Region的RegionName属性将成为Character的唯一标识的一员;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong style="font-size: 18pt;"&gt;Information Engineering - IE模型&lt;/strong&gt;&lt;br style="font-size: 18pt;" /&gt;Information Engineering采用Crow's Foot表示法（也有叫做James Martin表示法的），中文翻译中对使用了Crow's Foot表示法的模型也有笼统的称做鸭掌模型的（关联关系的关联基数中采用到了一个鸭掌形的三叉线来表示）。他由Clive Finkelstein发明，与James Martin一起推广，后来两人各自做了些修正形成两份版本&lt;br /&gt;前面示例模型的Information Engineering表示如下：&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/design/ERD-IE-Model.jpg" height="134" width="536" /&gt;&lt;br /&gt;图：Information Engineering - IE模型 - Crow's Foot Model - 鸭掌模型图：Information Engineering - IE模型&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #808080;"&gt;注意IE模型与ER模型的区别。Purchase Order与Party是多对一 n:1 的关联关系，在ER模型中n被放置在了Party的左边，而IE模型中n被放置在了Purchase Order的右边。两种表示法的形式（相当于语法）不一样，但语义是一致的。这一点也只有ER模型是特殊的，其他模型表示法中都与IE 模型一致&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Entity &amp;amp; Attribute&lt;/strong&gt;：实体属性并不出现在IE模型中，而是单独使用另外的文档记录&lt;br /&gt;&lt;strong&gt;Relationship&lt;/strong&gt;&lt;br /&gt;Crow's Foot的可选项optionality和关联基数cardinality 表示法：&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/design/ER/ERD-crows-foot-notation.jpg" height="93" width="484" /&gt;&lt;br /&gt;图：Crow's Foot的可选项optionality和关联基数cardinality 表示法图：Crow's Foot的可选项optionality和关联基数cardinality 表示法&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Optionality 可选项&lt;/strong&gt;：用来表示该关联关系是可选的，还是必须的。对于可选的关联关系，通常表现为用于关联的外键字段允许为null值，或者对于使用中间关联关系表的情况下可以不出现关联数据，而必须的关联关系则不允许外键为null或者必须存在关联数据&lt;br /&gt;&lt;strong&gt;Cardinality 关联基数&lt;/strong&gt;：用来表示关联实体的数量上限，为1、n等&lt;br /&gt;图中右边部分表示的意义如下：1个A必须关联到1个或多个B，一个B可以关联0个或1个A&lt;br /&gt;&lt;br /&gt;关联的约束如图所示，Product和Service通过一个圆连接到Order Line。如果是实心圆则表示Product和Service是exclusive or；如果是空心圆则表示Product和Service是inclusive or（相容的，conjunctive），表示可以是其中之一或者多个&lt;br /&gt;在上面IE模型图中，Order Line右侧是Finkelstein的一个特殊符号，表示一个Purchase Order初始时有0或n个Order Line，但最终必须有1或n个Order Line&lt;br /&gt;Martin以动词命名关联关系，只命名一个方向（遵循从左到右、从上往下的方式），而Finkelstein不对关联关系命名&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Sub-type&lt;/strong&gt;：图中Party子类的表示方法由Martin采用，Finkelstein则对每个子类使用单独的实体，使用ISA关联关系（关联关系名称为ISA，也有采用类似UML继承的三角形符合，在关联线上使用一个三角形的）表示其为子类&lt;br /&gt;&lt;br /&gt;&lt;strong style="font-size: 18pt;"&gt;Richard Barker's Notation&lt;/strong&gt;&lt;br style="font-size: 18pt;" /&gt;这个表示法最早是英国咨询公司CACI发明，经过了Richard Barker的推广，后来Richard Barker去了Oracle，开发了相关的建模工具，因此也叫做Oracle表示法（Oracle's Notation）&lt;br /&gt;示例模型的Barker表示法如下：&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/design/ER/ERD-Barker-Model.jpg" height="250" width="556" /&gt;&lt;br /&gt;Richard Barker's Model图：Richard Barker模型&lt;br /&gt;&lt;br /&gt;Entity &amp;amp; Attribute：实体试用圆角的方框表示，属性出现在实体框中。可选属性（允许null）前面带一个空心圆，必须的属性（不允许null）前面带一个实心圆，唯一标识属性前面带一个#符号（因为制图工具原因，有时可选属性前面不使用任何符号，必须属性前使用一个点）&lt;br /&gt;&lt;br /&gt;Relationship：&lt;br /&gt;Barker表示法中可选项通过半边连接线的虚实线表示，表示法如下图所示。上面的模型中Purchase Order必须关联到一个Party，所以关联线在Party一侧的那一半是实线表示；而Party可以关联到0或多个Purchase Order，所以关联线在Purchase Order一侧的那一半是虚线表示&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/design/ER/ERD-Barker-notation.jpg" height="134" width="219" /&gt;&lt;br /&gt;图：Richard Barker's Notation图：Richard Barker's Notation&lt;br /&gt;&lt;br /&gt;关联基数为n时采用一个三叉线，线条末端没有符号时表示关联基数为1&lt;br /&gt;另外Barker表示法中有一个表示aggregation、composition的特殊符号，例如示例模型中的Purchase Order和Order Line的关系，在Order Line右侧的三叉线边上添加一个竖线，注意与Crow's Foot表示法之间的区别&lt;br /&gt;Sub-type：Barker表示法中子类型显示在父类型的实体框中&lt;br /&gt;Constraint：Barker表示法仅支持exclusive or约束，如示例模型中所示，用一条弧线划过2个关联关系&lt;br /&gt;&lt;br /&gt;&lt;strong style="font-size: 18pt;"&gt;IDEF1X模型&lt;/strong&gt;&lt;br style="font-size: 18pt;" /&gt;IDEF1X是美国联邦政府广泛使用的一种模型，前面示例模型的IDEF1X等效模型如下：&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/design/ER/ERD-IDEF1X-Model.jpg" height="364" width="641" /&gt;&lt;br /&gt;图：IDEF1X模型图：IDEF1X模型&lt;br /&gt;&lt;br /&gt;Entity &amp;amp; Attribute：实体使用方框和圆角框表示，独立实体（Independent entities，主键不包含其他实体主键值）使用方框，非独立实体（dependent entities，主键包含其他实体主键值）使用圆角框。属性出现在实体框中，主键用线隔开&lt;br /&gt;&lt;br /&gt;Relationship：&lt;br /&gt;外键不是使用关联线表示，必须在实体属性中明确的标注外键属性&lt;br /&gt;如果关联关系一方的唯一标识将作为另一方唯一标识的一部分（即identifying relationship），关联线使用实线，否则（即non-identifying relationship）使用虚线&lt;br /&gt;&lt;br /&gt;不同于IE模型，IDEF1X中可选项和关联基数是分开表示的，关联线的一端表示关联基数，另一端表示可选项&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/design/ER/ERD-IDEF1X-notation.jpg" height="130" width="401" /&gt;&lt;br /&gt;图：IDEF1X Cardinality 关联基数图示图：IDEF1X Cardinality 关联基数图示&lt;br /&gt;如IDEF1X示例模型中，关联基数的图示都是出现在关联关系的左端或者上面，可选项出现在右端或者下面。对于可选的关联关系（即类似外键允许为null 值的情况），在可选项一端使用一个菱形，例如示例模型中Event Category左边的菱形；对于必须的关联关系（即外键必须为有效的实体标识值的情况），则在可选项一端直接将关联线与实体连接。对于多对多的情况，两端均使用关联基数符号，可选项问题在模型中通过其他文档标注&lt;br /&gt;&lt;br /&gt;关联关系的名称有几种表示方法。默认情况下遵循从左至右从上至下的顺序，关联关系从左至右的名称放在关联线上方，从右至左的名称放在关联线下方。也可以使用一个反斜杠将两个方向的名称分开，从左至右从上至下的在反斜杠前面，否则在后面&lt;br /&gt;&lt;br /&gt;Sub-type &amp;amp; Constraint&lt;br /&gt;IDEF1X中的子类和关联约束分别如示例模型中所示。另外一点，示例模型中的子类和关联约束图例中，小圆圈下面都是使用2条横线，这表示模型中已经列举了所有的子类和约束情况，如果模型只是部分列举子类和约束情况，则使用1条横线&lt;br /&gt;Domain：IDEF1X中定义了domain，domain即数据类型的定义，比如数据类型、取值范围等各种需要运用到属性值上的约束&lt;br /&gt;详尽的IDEF1X规范参考IDEF1X标准：&lt;a target="_blank" href="http://www.itl.nist.gov/fipspubs/idef1x.doc"&gt;Integration Definition for Information Modeling&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong style="font-size: 18pt;"&gt;EXPRESS-G表示法&lt;/strong&gt;&lt;br style="font-size: 18pt;" /&gt;EXPRESS-G是一个ISO标准ISO 10303-11。示例模型的EXPRESS-G表示法如下（省略了Event、Event Category部分）：&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/design/ER/ERD-EXPRESS-G-Model.jpg" height="243" width="653" /&gt;&lt;br /&gt;图：EXPRESS-G表示法图：EXPRESS-G表示法&lt;br /&gt;&lt;br /&gt;Entity &amp;amp; Attribute：&lt;br /&gt;实体使用方框表示，实体名称出现在方框中&lt;br /&gt;属性通过空心圆结束的线条连接到属性值类型，属性名称出现在线条上。可选属性使用虚线条连接，必须属性使用实现连接&lt;br /&gt;属性值类型使用右边多一条竖线的方框表示，ISO规范中确定的简单数据类型（String, Binary, Logical, Boolean, Number, Integer, Real等）均使用上图中所示的实体框表示。扩展或者自定义的数据类型使用虚线框表示，例如上图示例中order_date属性的DATE类型。枚举类型的表示方法如下图：&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/design/ER/ERD-EXPRESS-G-enum.jpg" height="40" width="253" /&gt;&lt;br /&gt;图：EXPRESS-G的枚举表示方法图：EXPRESS-G的枚举表示方法&lt;br /&gt;&lt;br /&gt;Relationship：&lt;br /&gt;使用空心圆结束的线条连接关联实体&lt;br /&gt;关联关系的名称出现在关联线上，朝空心圆一端的方向为正向，相反则为反向，反向的关联关系名称前面使用(INV)表示&lt;br /&gt;关联基数紧随关联名称之后，第一个字符可以是S、B、L、A，分别表示Set、Bag、List、Array，后面中括号的内容即为关联基数，问号表示多个。默认情况下（没有明确标注）关联基数都为[1:1]，因此上图中出现[1:1]的地方都可以省略&lt;br /&gt;&lt;br /&gt;前面提到过的exclusive or约束，EXPRESS-G中使用Select（可选类型）表示，如上图中的order_line_item&lt;br /&gt;&lt;br /&gt;Sub-type：如上图中Party、Person、Organization所示，连接线使用粗线条&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;ORM - Object-Role Modeling&lt;/strong&gt;&lt;br /&gt;下面是ORM2的部分表示法&lt;br /&gt;&lt;strong&gt;基本元素&lt;/strong&gt;&lt;br /&gt;下面是ORM模型几个基本元素图示：&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/design/ER/ORM-notation-basis.jpg" height="277" width="666" /&gt;&lt;br /&gt;图：ORM模型基本元素图：ORM模型基本元素&lt;br /&gt;&lt;br /&gt;唯一性约束表示法&lt;br /&gt;ORM中唯一性约束是在相应角色上使用带箭头的线条表示，线条在哪些角色上，则这些角色的组合必须唯一，例如下图：&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/design/ER/ORM-UC-internal.jpg" height="89" width="322" /&gt;&lt;br /&gt;图：ORM模型唯一性约束表示法图：ORM模型唯一性约束表示法&lt;br /&gt;图中Person is of Gender的关系中，Person必须唯一，因此这是一个n:1的关系。同样Person was born in Country是1:n，Person speaks Language是n:m，Person is president of Country是1:1&lt;br /&gt;&lt;br /&gt;下面表格是用于理解Person is of Gender、Person was born in Country的数据示例：&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/design/ER/ORM-unique-data-case.JPG" height="87" width="221" /&gt;&lt;br /&gt;图：数据示例&lt;br /&gt;&lt;br /&gt;关联关系中必须的角色使用带圆点的线条表示，如上图中Person was born in Country&lt;br /&gt;上面示例中的唯一性约束都是位于一个关联关系（包括二元和多元关系）中，这种唯一约束叫做内部唯一约束Internal UC。多个关联关系组合起来形成的唯一约束称为外部唯一约束External UC，例如下图所示&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/design/ER/ORM-UC-external.JPG" height="121" width="199" /&gt;&lt;br /&gt;图：ORM模型External UC图：ORM模型External UC&lt;br /&gt;图中State具有2个外部唯一约束，一个是Country+StateCode，圆圈中使用2跟线条表示这个唯一约束作为State的主键；另一个是 Country+StateName&lt;br /&gt;&lt;br /&gt;Inclusive or ((disjunctive mandatory role)&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/design/ER/ORM-inclusive-or.JPG" height="97" width="206" /&gt;&lt;br /&gt;图：ORM Inclusive or表示每个Visitor必须有护照Passport或者驾驶执照DriverLicence，或者两样都有&lt;br /&gt;&lt;br /&gt;Exclusive&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/design/ER/ORM-exlusive.JPG" height="97" width="224" /&gt;&lt;br /&gt;图：ORM Exclusive约束表示Person不可能同时是married和widowed状态&lt;br /&gt;&lt;br /&gt;exclusive or则是inclusive or和exclusive的结合，即必须是其中之一&lt;br /&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/design/ER/ORM-exlusive-or.JPG" height="91" width="224" /&gt;&lt;br /&gt;图：ORM Exclusive or约束&lt;br /&gt;&lt;br /&gt;详细的ORM2图形表示法参考&lt;a target="_blank" href="http://www.orm.net/pdf/ORM2GraphicalNotation.pdf"&gt;ORM 2 Graphical Notation Summary&lt;/a&gt;&lt;br /&gt;使用ORM建模的过程示例参考&lt;a target="_blank" href="http://www.orm.net/pdf/ORMwhitePaper.pdf"&gt;Object Role Modeling: An Overview&lt;/a&gt;&lt;br /&gt;ORM2的完整介绍参考&lt;a target="_blank" href="http://www.orm.net/pdf/ORM2.pdf"&gt;ORM2&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong style="font-size: 18pt;"&gt;参考&lt;/strong&gt;&lt;br style="font-size: 18pt;" /&gt;&lt;a target="_blank" href="http://en.wikipedia.org/wiki/Entity-relationship_model"&gt;Wiki - Entity-relationship model&lt;/a&gt;&lt;br /&gt;&lt;a target="_blank" href="http://en.wikipedia.org/wiki/IDEF1X"&gt;Wiki - IDEF1X&lt;/a&gt;&lt;br /&gt;&lt;a target="_blank" href="http://www.agiledata.org/essays/dataModeling101.html"&gt;Data Modeling 101&lt;/a&gt;&lt;br /&gt;&lt;a target="_blank" href="http://en.wikipedia.org/wiki/EXPRESS_%28data_modeling_language%29"&gt;Wiki - EXPRESS (data modeling language)&lt;/a&gt;&lt;br /&gt;&lt;a target="_blank" href="http://tc3.iec.ch/txt/xpress.pdf"&gt;Information modelling - Getting started with EXPRESS-G&lt;/a&gt;&lt;br /&gt;&lt;a target="_blank" href="http://en.wikipedia.org/wiki/Object_Role_Modeling"&gt;Wiki - Object-Role Modeling&lt;/a&gt;&lt;br /&gt;&lt;a target="_blank" href="http://www.orm.net/"&gt;Object Role Modeling&lt;/a&gt;&lt;br /&gt;&lt;a target="_blank" href="http://www.essentialstrategies.com/publications/modeling/compare.htm"&gt;A Comparison of Data Modeling Techniques&lt;/a&gt;&lt;img src="http://www.cnblogs.com/RicCC/aggbug/1824771.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/RicCC/archive/2010/09/13/Data-Modeling-Technologies.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/RicCC/archive/2010/09/13/1824742.html</id><title type="text">计划清单</title><summary type="text">备案不是一般的麻烦，个人博客上线暂缓确定重点关注的领域为：数据库、编译原理、伸缩性架构，以及看完Windows Internals 5th Edition数据库方面到此为止了，接下来是Antlr计划清单：1. 数据库 对关系数据库理论以及事物并发控制和恢复理论进行了一定了解，数据库方面到此为止。以后如果再有计划应该考虑看看MySQL源码了。Finished: 2010-09-132. 编译原理 a). 研究NHibernate HQL解析机制 b). 看完《The Definitive Antlr Reference》 - Finished: 2010-12-13 c). 看完龙书的后面部分 </summary><published>2010-09-13T01:45:00Z</published><updated>2010-09-13T01:45:00Z</updated><author><name>riccc</name><uri>http://www.cnblogs.com/RicCC/</uri></author><link rel="alternate" href="http://www.cnblogs.com/RicCC/archive/2010/09/13/1824742.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/RicCC/archive/2010/09/13/1824742.html"/><content type="html">备案不是一般的麻烦，个人博客上线暂缓&lt;br /&gt;确定重点关注的领域为：数据库、编译原理、伸缩性架构，以及看完Windows Internals 5th Edition&lt;br /&gt;数据库方面到此为止了，接下来是Antlr&lt;br /&gt;&lt;br /&gt;计划清单：&lt;br /&gt;&lt;span style="color: #339966;"&gt;1. 数据库&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #339966;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;对关系数据库理论以及事物并发控制和恢复理论进行了一定了解，数据库方面到此为止。以后如果再有计划应该考虑看看MySQL源码了。Finished: 2010-09-13&lt;br /&gt;&lt;/span&gt;2. 编译原理&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #ff6600;"&gt;a). 研究NHibernate HQL解析机制&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: #339966; "&gt;b). 看完《The Definitive Antlr Reference》 - Finished: 2010-12-13&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; c). 看完&lt;/span&gt;龙书的后面部分&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; d). 研究一个完整的编译器，候选：Firefox的JS、SSCLI&lt;br /&gt;3. 伸缩性架构&lt;br /&gt;4. Windows Internals 5th Edition&lt;img src="http://www.cnblogs.com/RicCC/aggbug/1824742.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/RicCC/archive/2010/09/13/1824742.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/RicCC/archive/2010/08/26/1808836.html</id><title type="text">声明：***本博客停止更新维护***</title><summary type="text">因为：1. 博客园内容的组织方式无法满足自己的要求；2. 系统速度经常很慢；3. 鱼龙混杂太吵太闹，新文章中有价值的越来越少，无谓的争吵讨论越来越多所以自己花时间写了个博客系统，以后本博客停止任何更新维护。本以为我的地盘我做主，可以更好的管理自己的内容，但内容的组织确实是个麻烦事，blog、 wiki、bbs、twiter等各种方式都无法达到理想的状况，只能说目前的web技术对内容组织呈现还是太过局限了。目前博客系统的主要功能已经好了，剩下的事情包括功能的完善、博客园文章内容的导入，以及个人网站的空间购买、备案等，估计2、3个月后会开通个人网站。</summary><published>2010-08-26T02:37:00Z</published><updated>2010-08-26T02:37:00Z</updated><author><name>riccc</name><uri>http://www.cnblogs.com/RicCC/</uri></author><link rel="alternate" href="http://www.cnblogs.com/RicCC/archive/2010/08/26/1808836.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/RicCC/archive/2010/08/26/1808836.html"/><content type="html">因为：&lt;br /&gt;1. 博客园内容的组织方式无法满足自己的要求；&lt;br /&gt;2. 系统速度经常很慢；&lt;br /&gt;3. 鱼龙混杂太吵太闹，新文章中有价值的越来越少，无谓的争吵讨论越来越多&lt;br /&gt;所以自己花时间写了个博客系统，以后本博客停止任何更新维护。本以为我的地盘我做主，可以更好的管理自己的内容，但内容的组织确实是个麻烦事，blog、wiki、bbs、twiter等各种方式都无法达到理想的状况，只能说目前的web技术对内容组织呈现还是太过局限了。&lt;br /&gt;&lt;br /&gt;目前博客系统的主要功能已经好了，剩下的事情包括功能的完善、博客园文章内容的导入，以及个人网站的空间购买、备案等，估计2、3个月后会开通个人网站。&lt;br /&gt;系统预览：&lt;br /&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/riccc/1.JPG" target="_blank" title="点击查看大图"&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/1.JPG" width="700" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/riccc/2.JPG" target="_blank" title="点击查看大图"&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/2.JPG" width="700" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/riccc/3.JPG" target="_blank" title="点击查看大图"&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/3.JPG" width="700" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/riccc/4.JPG" target="_blank" title="点击查看大图"&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/4.JPG" width="700" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/riccc/5.JPG" target="_blank" title="点击查看大图"&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/riccc/5.JPG" width="700" /&gt;&lt;/a&gt;&lt;img src="http://www.cnblogs.com/RicCC/aggbug/1808836.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/RicCC/archive/2010/08/26/1808836.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/RicCC/archive/2010/05/23/antlr-sql-parser.html</id><title type="text">ANTLR SQL解析器代码</title><summary type="text">博客里有一篇文章ANTLR实现的SQL解析器 - OQL，大概描述了一下用antlr实现的一个简单的sql解析器有不少人对antlr感兴趣，希望提供这个项目的源代码作为参考，一直没有放出来，原因有以下几个方面：1. antlr版本问题。开发时使用的antlr版本不久之后就更新了，与之前的老版本（包括项目中使用的）不兼容，项目中的语法文件已经无法在目前的antlr版本下使用这次上传的项目中包括当时使...</summary><published>2010-05-23T05:37:00Z</published><updated>2010-05-23T05:37:00Z</updated><author><name>riccc</name><uri>http://www.cnblogs.com/RicCC/</uri></author><link rel="alternate" href="http://www.cnblogs.com/RicCC/archive/2010/05/23/antlr-sql-parser.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/RicCC/archive/2010/05/23/antlr-sql-parser.html"/><content type="text">博客里有一篇文章ANTLR实现的SQL解析器 - OQL，大概描述了一下用antlr实现的一个简单的sql解析器有不少人对antlr感兴趣，希望提供这个项目的源代码作为参考，一直没有放出来，原因有以下几个方面：1. antlr版本问题。开发时使用的antlr版本不久之后就更新了，与之前的老版本（包括项目中使用的）不兼容，项目中的语法文件已经无法在目前的antlr版本下使用这次上传的项目中包括当时使...</content></entry><entry><id>http://www.cnblogs.com/RicCC/archive/2010/04/14/hibernate-shards-3-architecture.html</id><title type="text">Hibernate Shards 数据的水平、垂直切割（三）- Hibernate Shards结构</title><summary type="text">主要处理方式hibernate shards的主要工作方式如下图: 他在hibernate的基础上实现了一层数据切分的处理逻辑。不需要切分的数据直接使用hibernate的SessionFactory和Session进行操作；需要切分的数据，则使用hibernate shards的ShardedSessionFactory和ShardedSession进行操作hibernate shards的主要...</summary><published>2010-04-14T02:41:00Z</published><updated>2010-04-14T02:41:00Z</updated><author><name>riccc</name><uri>http://www.cnblogs.com/RicCC/</uri></author><link rel="alternate" href="http://www.cnblogs.com/RicCC/archive/2010/04/14/hibernate-shards-3-architecture.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/RicCC/archive/2010/04/14/hibernate-shards-3-architecture.html"/><content type="text">主要处理方式hibernate shards的主要工作方式如下图: 他在hibernate的基础上实现了一层数据切分的处理逻辑。不需要切分的数据直接使用hibernate的SessionFactory和Session进行操作；需要切分的数据，则使用hibernate shards的ShardedSessionFactory和ShardedSession进行操作hibernate shards的主要...</content></entry><entry><id>http://www.cnblogs.com/RicCC/archive/2010/04/10/hibernate-shards-2-shards-demo.html</id><title type="text">Hibernate Shards 数据的水平、垂直切割（二）- Hibernate Shards基本演示</title><summary type="text">准备1. 以Hibernate Shards 数据的水平、垂直切割（一）- Hibernate测试环境的项目为基础2. Hibernate Shards使用了commons logging，下载个项目最新的release版本。这里用的版本为1.1.13. 在Hibernate Shards 数据的水平、垂直切割（一）- Hibernate测试环境中，我们在mysql中建立了一个hbshards数据...</summary><published>2010-04-10T15:53:00Z</published><updated>2010-04-10T15:53:00Z</updated><author><name>riccc</name><uri>http://www.cnblogs.com/RicCC/</uri></author><link rel="alternate" href="http://www.cnblogs.com/RicCC/archive/2010/04/10/hibernate-shards-2-shards-demo.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/RicCC/archive/2010/04/10/hibernate-shards-2-shards-demo.html"/><content type="text">准备1. 以Hibernate Shards 数据的水平、垂直切割（一）- Hibernate测试环境的项目为基础2. Hibernate Shards使用了commons logging，下载个项目最新的release版本。这里用的版本为1.1.13. 在Hibernate Shards 数据的水平、垂直切割（一）- Hibernate测试环境中，我们在mysql中建立了一个hbshards数据...</content></entry><entry><id>http://www.cnblogs.com/RicCC/archive/2010/04/09/hibernate-shards-1-hbtest.html</id><title type="text">Hibernate Shards 数据的水平、垂直切割（一）- Hibernate测试环境</title><summary type="text">准备需要用到的东西如下，下载这几个项目最新的release版本:1. Hibernate Core，这里用的版本为3.5.0-final2. Hibernate Shards，这里用的版本为3.0.0-Beta23. MySql java connector，这里用的版本为5.1.124. slf4j，这里用的版本为1.5.115. 安装并启动mysql服务，在mysql中建立数据库hbshard...</summary><published>2010-04-09T14:44:00Z</published><updated>2010-04-09T14:44:00Z</updated><author><name>riccc</name><uri>http://www.cnblogs.com/RicCC/</uri></author><link rel="alternate" href="http://www.cnblogs.com/RicCC/archive/2010/04/09/hibernate-shards-1-hbtest.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/RicCC/archive/2010/04/09/hibernate-shards-1-hbtest.html"/><content type="text">准备需要用到的东西如下，下载这几个项目最新的release版本:1. Hibernate Core，这里用的版本为3.5.0-final2. Hibernate Shards，这里用的版本为3.0.0-Beta23. MySql java connector，这里用的版本为5.1.124. slf4j，这里用的版本为1.5.115. 安装并启动mysql服务，在mysql中建立数据库hbshard...</content></entry></feed>
