<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>71街 &#187; 范式设计</title>
	<atom:link href="http://www.71j.cn/archives/tag/%e8%8c%83%e5%bc%8f%e8%ae%be%e8%ae%a1/feed" rel="self" type="application/rss+xml" />
	<link>http://www.71j.cn</link>
	<description>杜工的技术博客</description>
	<lastBuildDate>Fri, 16 Dec 2011 03:52:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>范式设计简单介绍(二)</title>
		<link>http://www.71j.cn/archives/66</link>
		<comments>http://www.71j.cn/archives/66#comments</comments>
		<pubDate>Tue, 08 Sep 2009 05:29:59 +0000</pubDate>
		<dc:creator>杜工</dc:creator>
				<category><![CDATA[分享]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[范式设计]]></category>

		<guid isPermaLink="false">http://71j.cn/?p=66</guid>
		<description><![CDATA[NF 理论在设计之初，主要是为了应付数据冗余与存储重复而出的。当越来越庞大的数据库应用出现时，高度设计的 NF 带来的好处与性能所带来的坏处相互抵消了。因为通常，越高层次的 NF 会划... ]]></description>
			<content:encoded><![CDATA[<h2>1.3]  Third Normal Form(3NF)</h2>
<p>3NF 要求所有的属性都直接依赖于 primary key。3NF 和 2NF 最大的不同之处是，2NF 有依赖传递性,而 3NF 不准许。</p>
<p> 例如,有一个符合 2NF 的表：</p>
<p>错误方式：</p>
<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</p>
<p>..some属性s  | 用户号    | 用户发表文章数 | 用户登录数| 用户积分 |  other 列 &#8230;</p>
<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>……           |  ID_001 |    4           |     20    |    13    |    ……</p>
<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</p>
<p align="center">用户积分规则：用户发表文章数 x 2  + 用户登录数 /4</p>
<p>  在 3NF 中是不符合的。因为‘用户积分’是通过‘用户发表文章数’和‘用户登录数’，用公式计算得来的。也就是说，‘用户积分’依赖于‘用户发表文章数’和‘用户登录数’。</p>
<p>  3NF 符合的划分方式是：</p>
<p>正确方式：</p>
<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>..some属性s  | 用户号    | 用户发表文章数 | 用户登录数|  other 列 &#8230;</p>
<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>……           |  ID_001 |    4           |     20    |    ……</p>
<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>正确方式：</p>
<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>..some属性s  | 用户号    |  用户积分 |  other 列 &#8230;</p>
<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>……           |  ID_001 |     13    |    ……</p>
<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>用户积分规则不变</p>
<p> 需要注意的是，虽然 3NF 更加清楚地将用户资料和用户积分这两个关系表示了出来。但是在需要联合查询用户资料和积分的情况下，在大多数 RDBMS 如 MySQL 中，会造成性能消耗严重的情况。进一步讨论在 1.4 中进行。</p>
<p>              1.3.1]    Joining 关系</p>
<p> 关系之间相互关联的方式有两种：INNER　JOIN  和 OUTER JOIN</p>
<p>  INNER JOIN 查询会返回两个关系完全匹配的情况，MYSQL 默认的匹配方式为 INNER JOIN 。</p>
<p>  如果你希望查询的结果即使没有匹配也会被查询出来，那么就要使用 OUTER JOIN 的连接方式。OUTER JOIN 又细分为三种：LEFT OUTER JOIN, RIGHT OUTER JOIN 和 FULL OUTER JOIN 。</p>
<p>  LEFT　OUTER JOIN 是将左边的查询关系作为主关系，如果右面的关系有相匹配的 tuple , 那么处理方式和 INNER JOIN 一样；如果右面的关系没有与左边的关系相匹配，那么属性就会列出一个 NULL 的值。</p>
<p>  RIGHT OUTER JOIN 的处理方式与 LEFT OUTER JOIN 类似，只不过是以右面的关系为主 关系。</p>
<p>  FULL OUTER JOIN 与 INNER JOIN 的显示结果相同。</p>
<h3>            1.3.2]    BCNF</h3>
<p> 修正的第三范式(BCNF) 全称 Boyce-Codd normal form 。是 3NF 的一个拓展，所以 BCNF 的前提和 3NF 是一样的：关系 必须符合 2NF ，并且有 KEY 可以用来相互关联。并不是所有符合 2NF 的关系都可以划分为 BCNF。</p>
<p>  BCNF 简单来说，就是所有的 tuple 都依赖于 candidate key 或者这个 tuple 是 superkey 。因此所有的 tuple 都依赖于 key，从而避免了传递依赖问题。</p>
<h2>        1.4]  NF 设计与性能消耗</h2>
<p>NF 理论在设计之初，主要是为了应付数据冗余与存储重复而出的。当越来越庞大的数据库应用出现时，高度设计的 NF 带来的好处与性能所带来的坏处相互抵消了。因为通常，越高层次的 NF 会划分越多的 关系，从而查询出所需要的数据就需要更多的 join 操作。虽然 view 在一定程度上可以解决这个问题，但是视图本身也是一个不小的性能消耗。</p>
<p> 如果一个 MySQL 执行的多是 SQL-Transaction 的话，那么使用高层次的 NF 设计就显得尤为必要，因为书写 transaction 的 SQL 语言通常都不适于做复杂的过程处理，而高层次的 NF 设计可以在逻辑上更清楚的划分关系，从而较少的操作关系之间的关系处理，较多的操作关系之间的数据。</p>
<p> 而如果一个 MySQL 在应用中 ，更多的是扮演数据存储与统计的操作，那么高层次的 NF 设计就没有必要。因为此类应用中，通常都搭配使用高级编程语言，而高级编程语言灵活多样，在逻辑、过程与数据的处理过程中，都要比 SQL 更加的强壮。</p>
<h2>        1.5]  NF 与 SQL 的关系</h2>
<p>SQL 语言是为了结构化的查询数据而发明的一种机器查询语言。主要的功能是查询，兼顾数据定义与控制的功能。</p>
<p> SQL 大致可以分为三类：</p>
<h3>1.5.1]    Data Manipulation Language (DML)</h3>
<p>        DML 主要用来 查/删/改/插关系的 tuple 。他们共同的特点是都需要指定作用的关系和关系之间的关系。</p>
<p>        1.5.1.1]    Select</p>
<p>    Select 用来查询关系中的 tuple 包括:</p>
<p>        Select : 后面跟属性,作用是控制查询的输出。</p>
<p>        From : 后面跟关系与  joins ,作用是控制与关联关系之间的关系。</p>
<p>        Where : 后面跟属性的限制语句，主要是用来划分查询的区域。</p>
<p>        Group By : 后面跟属性,主要用来将相似的属性分成单一的结果集。</p>
<p>        Having : 与 Where 作用相同，作用域为 Group By 控制的结果集。</p>
<p>        Order By: 用来将最后筛选出来的结果集，通过某一 tuple 来进行排序。</p>
<p>    具体作用详见：1.2.1]</p>
<p>        1.5.1.2]    Insert</p>
<p>    Insert 用来插入 tuple。具体作用详见：1.2.2]</p>
<p>        1.5.1.3]    Update</p>
<p>    Update 用来更新 tuple 。具体作用详见：1.2.3]</p>
<p>        1.5.1.4]    Delete</p>
<p>    Delete 用来删除 tuple 。作用域与 Select 类似，但是不返回查询的 tuple。</p>
<h3>1.5.2]    Data Definition Language (DDL)</h3>
<p>        DDL 的作用是创建关系与定义关系中的属性。主要包括三大部分：</p>
<p>        1.5.2.1]  CREATE </p>
<p>    创建语句,可以用来创建 Database、关系、transaction(祥见 1.2.4) 等。根据需要创建的类型不同，语句稍有差别。</p>
<p>        1.5.2.2]  DROP</p>
<p>    删除语句，与 CREATE 语句相反。</p>
<p>        1.5.2.3]  ALTER</p>
<p>    修改关系和 Transaction 。</p>
<h3>1.5.3]    Data Control Language (DCL)</h3>
<p>        DCL 的作用是用来控制关系和属性的权限。主要有两部分：</p>
<p>        1.5.3.1]  GRANT</p>
<p>    用来创建访问关系与属性的权限</p>
<p>        1.5.3.2]  REVOKE</p>
<p>    用来删除访问关系与属性的权限</p>
<p>原文作者：韩述 杜工稍作修改。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.71j.cn/archives/66/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>范式设计简单介绍(一)</title>
		<link>http://www.71j.cn/archives/62</link>
		<comments>http://www.71j.cn/archives/62#comments</comments>
		<pubDate>Tue, 08 Sep 2009 05:27:03 +0000</pubDate>
		<dc:creator>杜工</dc:creator>
				<category><![CDATA[分享]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[范式设计]]></category>

		<guid isPermaLink="false">http://71j.cn/?p=62</guid>
		<description><![CDATA[ 范式设计是关系数据库的一个延伸理论。目的是在关系数据库的基础上，减少重叠数据的冗余，并且在将列(属性) 逐渐拆分成表(关系) 的过程中，从理论上减少了异常数据产生的几率。增强了... ]]></description>
			<content:encoded><![CDATA[<p>    范式设计是关系数据库的一个延伸理论。目的是在关系数据库的基础上，减少重叠数据的冗余，并且在将列(属性) 逐渐拆分成表(关系) 的过程中，从理论上减少了异常数据产生的几率。增强了数据的关系性能，在一定程度上，增强了关系查询效率。       </p>
<p>        术语：通常在具体的 RDBMS 如 MySQL 的应用开发中，将一个关系叫做表，一条元组（tuple） 称为行，一个属性叫做列。     因为范式（NF） 设计主要是讲理论，所以在本文中，一律将表称为关系，将行称为tuple，将列称为属性。</p>
<p>如图：</p>
<p><img class="aligncenter size-full wp-image-71" title="范式设计" src="http://71j.cn/wp-content/uploads/2009/09/范式设计.jpg" alt="范式设计" width="551" height="237" /></p>
<h2>        1.1]  First Normal Form(1NF)</h2>
<p>1NF(第一范式)  的目的是将数据拆分成原子状态。例如 一个大型文章发布系统的文章序列号的组成是 8 位用户名 + 该用户所属的文章号，如某用户的用户名是 ID_001 ，他发表的某一篇文章，在他的文章列表中的序列号是 15 ，这篇文章在该系统中唯一序列号是 ID_00115 。</p>
<p> 将文章序列号存储到关系中去，通常的做法是这样的：</p>
<p>错误的方式</p>
<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;+</p>
<p>some属性……  |   文章序列号    | other 列……</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>……|   ID_00115    |</p>
<p>这么做是不符合 1NF 规范的。因为文章序列号是两部分组成的，如果存成一个属性那么就违反了 1NF 的原子性原则。</p>
<p> 符合 1NF 的属性划分方法如下：</p>
<p> 正确方式：</p>
<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;+</p>
<p>some属性…… |  用户号  | 文章号 | other 列……</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>……| ID_001       |  15      |</p>
<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;+</p>
<h2>        1.2]  Second Normal Form（2NF）</h2>
<p>2NF 划分关系的原则是：一个关系中的所有非 Key属性s 必须完全的依赖于 Key。如果是多主键的话，那么非主键属性s 必须完全依赖所有的主键.</p>
<p> 1NF 的范围是同一关系的不同属性之间的划分。而 2NF(第二范式) 的范围是将一个大的，数据相互重叠与冗余的关系拆分成众多小的，关系 ，他们之间相互的联系就是 Key ，Key 是一个关系中唯一标示一个tuple 的标识。而且在 2NF 中，所有有效的单一的 Key 默认都是 Primary key。(多个 Key 唯一定位一个tuple ,那么这些Key 称为复合主键) 。</p>
<p> 另外一点需要特别注意的是，范式是属性递增的，因此，只有在完成了 1NF 之后，才能进行 2NF 的划分。</p>
<p> 例如某文章系统中，一个存储某一篇文章的关系，有如下字段 </p>
<p>错误方式：</p>
<p> +&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</p>
<p>..some属性s       |  用户号    |  文章号  |  文章标题 |  文章内容 | 文章创建时间 | 用户发表文章数 | 用户登录数| other 列 &#8230;</p>
<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</p>
<p>……|   ID_001 |   15     |  Article  | Cnt &#8230;   |  1223372589  |      4         |     20    |  ……</p>
<p> 其中，‘用户号’和‘文章号’对于 ‘文章标题’、‘文章内容’、‘文章创建时间’来说，可以算是复合主键，因为要查出这些属性，必须完全依赖 ‘文章号’和 ‘用户号’这两个属性，缺一不可。</p>
<p> 而 ‘用户发表文章数’和 ‘用户登录数’这两个属性仅依靠 ‘用户号’就可以出来，所以 ‘用户号’是 ‘用户发表文章数’和 ‘用户登录数’的主键，而 ‘文章号’则和这两个属性没有关系。也可以说 ‘用户发表文章数’和 ‘用户登录数’没有完全依赖于复合主键，所以这个表不符合 2NF 标准(但是所有属性都是原子不可分状态，因此这个表符合 1NF 标准)。</p>
<p> 如果要符合 2NF 标准，就需要将这个关系拆分成两个关系</p>
<p> 正确方式：</p>
<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>..some属性s       |  用户号    |  文章号  |  文章标题 |  文章内容 | 文章创建时间 | other 列 &#8230;</p>
<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>……|   ID_001 |   15     |  Article  | Cnt &#8230;   |  1223372589  |       ……</p>
<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;  </p>
<p> 正确方式：</p>
<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>..some属性s       |  用户号    |  用户发表文章数 | 用户登录数| other 列 &#8230;</p>
<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>……|   ID_001 |     4           |     20    |  ……</p>
<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-  </p>
<p> 这样，Right way one . 中剔出了不符合完全依赖的两个属性s ，所有的属性s 都完全依赖 composite primary key ，可以认为 Right way one. 符合 2NF 标准。</p>
<p>另外，将 Wrong way. 中剔出的两个属性s 划分到了 Right way two. 里面，primary key 是 ‘用户号’。因此 Right way two. 仅就一个 primary key ，并且所有内容都依赖于 primary key 查询，所以可以说 Right way two. 符合 2NF 的要求。</p>
<h3>            1.2.1]   关系模式</h3>
<p>经过 2NF 的拆分，现在关系的数量在增加，但是属性之间的关系趋向于更加的简单明了。 </p>
<p>关系之间根据对应联系的不同，有三种不同的关系模式：</p>
<p>    ·  一对一</p>
<p>    ·  一对多</p>
<p>    ·  多对多</p>
<p> ·一对一 ， 既一个属性仅可以对应一个其他的属性</p>
<p>    例如：一个用户号和用户之间就是一对一的关系，一个用户只能有一个用户号，一个用户号只能指定某一个用户。</p>
<p>·一对多 ， 既一个属性可以对应多个其他的属性</p>
<p>    例如: 一个用户号可以对应多个文章号,因为用户可以发表多篇的文章.</p>
<p>·多对多 ， 既多个属性可以对应多个其他的属性</p>
<p>    完全多对多就是 Cartesian product(笛卡尔积或直积)。</p>
<p>    例如: 一个用户可以发相同标题的不同文章。而拥有相同标题的文章，可以由不同的用户发。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.71j.cn/archives/62/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

