??xml version="1.0" encoding="utf-8" standalone="yes"?>jzzjzzjzz亚洲成熟少妇,欧美一区日韩一区,69久久精品http://www.aygfsteel.com/weibogao/category/19122.htmlmy second lifespacezh-cnWed, 28 Feb 2007 02:12:30 GMTWed, 28 Feb 2007 02:12:30 GMT60Oracle的物化视?/title><link>http://www.aygfsteel.com/weibogao/archive/2007/01/15/93914.html</link><dc:creator>weibogao</dc:creator><author>weibogao</author><pubDate>Mon, 15 Jan 2007 04:05:00 GMT</pubDate><guid>http://www.aygfsteel.com/weibogao/archive/2007/01/15/93914.html</guid><wfw:comment>http://www.aygfsteel.com/weibogao/comments/93914.html</wfw:comment><comments>http://www.aygfsteel.com/weibogao/archive/2007/01/15/93914.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/weibogao/comments/commentRss/93914.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/weibogao/services/trackbacks/93914.html</trackback:ping><description><![CDATA[     摘要: Oracle 的物化视图提供了(jin)强大的功能,可以用在不同的环境中。在不同的环境中Q物化视囄作用也不相同? 数据仓库中的物化视图主要用于预先计算q保存表q接或聚集等耗时较多的操作的l果Q这P在执行查询时Q就可以避免q行q些耗时的操作,而从快速的得到l果。在数据仓库中,q经怋用查询重写( ...  <a href='http://www.aygfsteel.com/weibogao/archive/2007/01/15/93914.html'>阅读全文</a><img src ="http://www.aygfsteel.com/weibogao/aggbug/93914.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/weibogao/" target="_blank">weibogao</a> 2007-01-15 12:05 <a href="http://www.aygfsteel.com/weibogao/archive/2007/01/15/93914.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Effective SQLhttp://www.aygfsteel.com/weibogao/archive/2007/01/12/93392.htmlweibogaoweibogaoFri, 12 Jan 2007 04:56:00 GMThttp://www.aygfsteel.com/weibogao/archive/2007/01/12/93392.htmlhttp://www.aygfsteel.com/weibogao/comments/93392.htmlhttp://www.aygfsteel.com/weibogao/archive/2007/01/12/93392.html#Feedback1http://www.aygfsteel.com/weibogao/comments/commentRss/93392.htmlhttp://www.aygfsteel.com/weibogao/services/trackbacks/93392.html一.名词解释Q?
0。SQL l构化查询语a(Structured Query Language)

1。非关系型数据库pȝ
做ؓ(f)W一代数据库pȝ的ȝQ其包括2U类型:(x)“层ơ”数据库与“网状”数据库

“层ơ”数据库理pȝ eg:IBM&IMS (Information  Management System)
特点:数据按层ơ模型组l?

"|状"数据?
特点Q数据按|状模型l织

2。关pd数据库系l?
关系性数据库理pȝ (RDBMS)
eg:SQL/DS , DB2, Oracle ,Informix ,Unity,dBASE{?
特点Q数据按二维的表格组l?

3。数据库(DataBase)
按一定结构存储在计算Z怺兌的数据的集合?

4。数据库理pȝDBMS(Database Management System)
一个通用的Y件系l。就是让你怎么理你的数据库。其中包括存储,安全Q完整性管?br />{?

5。数据库应用pȝDBAS QDatabase Application SystemQ?
数据库应用程序系l,建立在DBMS基础之上的。就是一个面向用L(fng)软gpȝ?

6。ANSI标准 QAmerican National Standards InstituteQ美国国家标准委员会(x)
因ؓ(f)1999q第2ơ更新SQLQ所以SQL又称为SQL99或SQL3Q第3版,?个版本分别ؓ(f)1986q?br />的sql ,1992 q的sql2/sql92Q?

7。SQL语句?U类?
数据操作语句(Data Manipulation Language ) DML 关于数据操作命o(h)的?eg:select,in
sert,update,delete
数据定义语句(Data Definition Language ) DDL     关于数据对象讉K的?eg:createQ?br /> drop
数据控制语句(Data Control Language) DCL         关于权限的?eg:grant Qrevoke


8。PL/SQL Procedural Language/sql
用于oracle的语a

9.T-SQL  transact-sql
用于 microsoft sql server 和sybase adaptive server

10。E.F.Codd关于关系型数据库12条检验原则(MYSQLQ不支持视图和原子事物处理,所?br />排除Q?
内容Q暂?

11。数据库设计之新奥尔良方法?
需求分?=》概念设?=》逻辑设计==》物理设?
4个步骤的具体中以需求分析最重要.
需求分析的内容:暂略
概念设计的内?暂略
逻辑设计的内?暂略
物理设计的内?暂略


?数据库优化方?
1.索引
一 概述

  可以利用索引快速访问数据库表中的特定信息。烦(ch)引是Ҏ(gu)据库表中一个或多个列的?br />q行排序的结构?
  索引提供指针以指向存储在表中指定列的数据|然后Ҏ(gu)指定的排序次序排列这些指
针?
  数据库用烦(ch)引的方式与用书的目录很怼Q通过搜烦(ch)索引扑ֈ特定的|
  然后跟随指针到达包含该值的?

索引是一个单独的、物理的数据库结构,它是某个表中一列或若干列值的集合和相应的?br />向表中物理标识这些值的数据늚逻辑指针清单?

一个表的存储是׃部分l成的,一部分用来存放表的数据面Q另一部分存放索引面
。烦(ch)引就存放在烦(ch)引页面上

?索引的两U类型:(x)

聚集索引=集索引

聚集索引Z数据行的键值在表内排序和存储这些数据行。由于数据行按基于聚集烦(ch)引键
的排序次序存储,
因此聚集索引Ҏ(gu)找行很有效。每个表只能有一个聚集烦(ch)引,因ؓ(f)数据行本w只能按一?br />序存储?
数据行本w构成聚集烦(ch)引的最低别?

只有当表包含聚集索引Ӟ表内的数据行才按排序ơ序存储。如果表没有聚集索引Q?
则其数据行按堆集方式存储?

聚集索引对于那些l常要搜索范围值的列特别有效。用聚集烦(ch)引找到包含第一个值的?br />后,
便可以确保包含后l烦(ch)引值的行在物理盔R。例如,如果应用E序执行的一个查询经常检
索某一日期范围
内的记录Q则使用聚集索引可以q速找到包含开始日期的行,然后(g)索表中所有相?c)?br />Q?
直到到达l束日期。这h助于提高此类查询的性能。同P如果对从表中(g)索的数据q?br />行排序时
l常要用到某一列,则可以将该表在该列上聚集Q物理排序)(j)Q避免每ơ查询该列时都进
行排序,
从而节省成?

非聚集烦(ch)?

非聚集烦(ch)引具有完全独立于数据行的l构。非聚集索引的最低行包含非聚集烦(ch)引的键|

q且每个键值项都有指针指向包含该键值的数据行。数据行不按Z非聚集键的次序存?br />?

在非聚集索引内,从烦(ch)引行指向数据行的指针UCؓ(f)行定位器?
行定位器的结构取决于数据늚存储方式是堆集还是聚集。对于堆集,行定位器是指向行
的指针?
对于有聚集烦(ch)引的表,行定位器是聚集烦(ch)引键?
只有在表上创Z(jin)聚集索引Ӟ表内的行才按特定的顺序存储。这些行基于聚集烦(ch)引键
按顺序存储?
如果一个表只有非聚集烦(ch)引,它的数据行将按无序的堆集方式存储
非聚集烦(ch)引可以徏多个,两者都能改善查询性能

非聚集烦(ch)引与聚集索引一h B ?wi)结构,但是有两个重大差别?x)
数据行不按非聚集索引键的序排序和存储?
非聚集烦(ch)引的叶层不包含数据页?
相反Q叶节点包含索引行。每个烦(ch)引行包含非聚集键g?qing)一个或多个行定位器Q?
q些行定位器指向有该键值的数据行(如果索引不唯一Q则可能是多行)(j)?
非聚集烦(ch)引可以在有聚集烦(ch)引的表、堆集或索引视图上定?


聚集索引-->序表结?其物理数据和逻辑排序紧邻.
非聚集烦(ch)?->单链表结?L(fng)理和逻辑排序不按序排列.

打个比方.
一本字?你现在查一个陈?你有2U方?首先,你在知道他念chen的情况下L照拼韛_
母去查找.他是排在字母A,B
于是你很Ҏ(gu)的就扑ֈ"??W?U方法则是按~旁查找,先找到x?LC个(f)?br />的编旁表在去??q个?然后按照l出?
|扑ֈ相应的位|?
昄,W一U方法就是聚集烦(ch)?按照物理位置Ҏ(gu)排序来查?
W?U方法则是非聚集索引,按照一个(f)时烦(ch)引来查找.

另外
唯一索引

唯一索引可以保索引列不包含重复的倹{在多列唯一索引的情况下Q该索引可以保?br />引列中每个值组
合都是唯一的。唯一索引既是索引也是U束?

复合索引
索引Ҏ(gu)多个的就叫组合烦(ch)引,也叫复合索引。复合烦(ch)引用时需要注意烦(ch)引项的次序?br />

?索引的创?

有两U方法可以在 SQL Server 内定义烦(ch)? CREATE INDEX 语句和CREATE TABLE 语句


CREATE TABLE支持在创建烦(ch)引时使用下列U束Q?

PRIMARY KEY 创徏唯一索引来强制执行主?
UNIQUE 创徏唯一索引
CLUSTERED 创徏聚集索引
NONCLUSTERED 创徏非聚集烦(ch)?

? 1 定义索引Ӟ可以指定每列的数据是按升序还是降序存储。如果不指定Q则默认?br />升序
   2 支持在计列上创建烦(ch)?
   3 为烦(ch)引指定填充因?
     可标识填充因子来指定每个索引늚填满E度。烦(ch)引页上的IZI间量很重要Q?
     因ؓ(f)当烦(ch)引页填满Ӟpȝ必须花时间拆分它以便为新行腾出空间?


?索引的维护语?

DBCC DBREINDEX    重徏指定数据库中表的一个或多个索引
DBCC INDEXFRAG  整理指定的表或视囄聚集索引和辅助烦(ch)引碎?

比较

            速度    兼容性   ?日志影响      数据讉K影响       额外盘I间

DBCC        最快    ?最q  ??但能通过把 ?操作q程中数据不   需要大
DBREINDEX             可以重 ?故障q原模型设?能访问,影响?
                     建所有 ?为简单减日志  ?
                     有烦(ch)?

DBCC        慢     ?但可   必须分 ?            ?数据未被锁定        需要小

INDEXDEFRAG          随时l?别指?
                    止执行 ?
                              

drop index    中等  必须分 ??但能通过把  ?仅在操作执行时  ?中等Q操作在 
 
create index        别指定 ?故障q原模型设 ?锁定数据          tempdb中进?

                            为简单减日?


?查看索引的方?

sp_indexes        q回指定q程表的索引信息
INDEXKEY_PROPERTY q回有关索引键的信息
sysindexespȝ表?数据库中的每个烦(ch)引和表在表中各占一行,该表存储在每个数据库?br />


?可以通过执行计划
  查看sql语句执行时是否徏立在索引之上

比如
CREATE TABLE Test
(Field_1 int NOT NULL,
Field_2 int CONSTRAINT PK_Test
PRIMARY KEY CLUSTERED (Field_1))

CREATE index IX_Test ON Test (Field_2)

1 SELECT * FROM Test WHERE Field_2 =408
执行计划可以看出使用?jin)IX_Test索引
2 SELECT * FROM Test WHERE Field_1 =1
执行计划可以看出使用?jin)PK_Test
3 但如果是SELECT * FROM Test with (index(IX_Test)) WHERE Field_1 =1
则指定用烦(ch)?


?索引的具体?

1Q?索引的设?
A:量避免表扫?
(g)查你的查询语句的where子句Q因是优化器重要x的地斏V包含在where里面的每
一列(column)都是可能的侯选烦(ch)引,辑ֈ最优的性能Q考虑在下面给出的例子Q对?br />在where子句中给Z(jin)column1q个列?
下面的两个条件可以提高烦(ch)引的优化查询性能Q?
W一Q在表中的column1列上有一个单索引
W二Q在表中有多索引Q但是column1是第一个烦(ch)引的?
避免定义多烦(ch)引而column1是第二个或后面的索引Q这L(fng)索引不能优化服务器性能
例如Q下面的例子用了(jin)pubs数据库?
SELECT au_id, au_lname, au_fname FROM authors
WHERE au_lname = ’White?
按下面几个列上徏立的索引会(x)是对优化器有用的索引
?au_lname
?au_lname, au_fname
而在下面几个列上建立的烦(ch)引将不会(x)对优化器起到好的作用
?au_address
?au_fname, au_lname
考虑使用H的索引在一个或两个列上Q窄(jing)索引比多索引和复合烦(ch)引更能有效。用H的索引
Q在每一上
会(x)有更多的行和更少的烦(ch)引别(相对与多索引和复合烦(ch)引而言Q,q将推进pȝ性能
?
对于多列索引QSQL Serverl持一个在所有列的烦(ch)引上的密度统计(用于联合Q和在第一
个烦(ch)引上?
histogramQ柱状图Q统计。根据统计结果,如果在复合烦(ch)引上的第一个烦(ch)引很被选择?br />用,那么优化器对很多查询h不?x)用?ch)引?
有用的烦(ch)引会(x)提高select语句的性能Q包括insert,uodate,delete?
但是Q由于改变一个表的内容,会(x)影响索引。每一个insert,update,delete语句会(x)?br />性能下降一些。实验表明,不要在一个单表上用大量的索引Q不要在׃n的列上(指在?br />表中用了(jin)参考约束)(j)使用重叠的烦(ch)引?
在某一列上(g)查唯一的数据的个数Q比较它与表中数据的行数做一个比较。这是数据?br />选择性,q比较结果将?x)帮助你军_是否某一列作Z选的索引列,如果需要,建哪一
U烦(ch)引。你可以用下面的查询语句q回某一列的不同值的数目?
select count(distinct cloumn_name) from table_name
假设column_name是一?0000行的表,则看column_nameq回值来军_是否应该使用Q及(qing)?br />该用什么烦(ch)引?
Unique values Index

5000 Nonclustered index
20 Clustered index
3 No index


2) 镞烦(ch)引和非镞索引的选择

<1:>镞烦(ch)引是行的物理序和烦(ch)引的序是一致的。页U,低层{烦(ch)引的各个U别上都?br />含实际的数据c(din)一个表只能是有一个镞索引。由于update,delete语句要求相对多一些的
L作,因此镞烦(ch)引常常能加速这L(fng)操作。在臛_有一个烦(ch)引的表中Q你应该有一个镞
索引?
在下面的几个情况下,你可以考虑用镞索引Q?
例如Q?某列包括的不同值的个数是有限的Q但是不是极的Q?
֮表的州名列有50个左右的不同州名的羃写|可以使用镞烦(ch)引?
例如Q?对返回一定范围内值的列可以用镞索引Q比如用between,>,>=,<,<={等来对?br />q行操作的列上?
select * from sales where ord_date between ?/1/93?and ?/1/93?
例如Q?Ҏ(gu)询时q回大量l果的列可以使用镞烦(ch)引?
SELECT * FROM phonebook WHERE last_name = ’Smith?

当有大量的行正在被插入表中时Q要避免在本表一个自然增长(例如Qidentity列)(j)的列
上徏立镞索引。如果你建立?jin)镞的?ch)引,那么insert的性能׃(x)大大降低。因为每一个插
入的行必d表的最后,表的最后一个数据页?
当一个数据正在被插入Q这时这个数据页是被锁定的)(j)Q所有的其他插入行必ȝ待直?br />当前的插入已l结束?
一个烦(ch)引的叶中包括实际的数据页Qƈ且在盘上的数据늚ơ序是跟镞烦(ch)引的逻辑
ơ序一L(fng)?

<2:>一个非镞的索引是行的物理ơ序与烦(ch)引的ơ序是不同的。一个非镞烦(ch)引的叶包含
?jin)指向行数据늚指针?
在一个表中可以有多个非镞索引Q你可以在以下几个情况下考虑使用非镞索引?
在有很多不同值的列上可以考虑使用非镞索引
例如Q一个part_id列在一个part表中
select * from employee where emp_id = ’pcm9809f?
查询语句中用order by 子句的列上可以考虑使用镞烦(ch)?



3) 一个表列如果设Z?primary key),它会(x)自动生成一个聚烦(ch)?
q时不能直接使用Drop index Table1.Tableindex1语句
必须删除主键U束Q用语句:alter table table1 drop constraint U束?如pk_xxx)



?全文索引
use pubs
  go

  --打开数据库全文烦(ch)引的支持

 execute sp_fulltext_database 'enable'
 go

  --建立全文目录ft_titles

  execute sp_fulltext_catalog 'ft_titles', 'create'
  go

  --为titles表徏立全文烦(ch)引数据元QUPKCL_titleidind是主键所建立的唯一索引Q可
由sp_help titles得知

  execute sp_fulltext_table 'titles','create', 'ft_titles', 'UPKCL_titleidin
d'
  go

  --讄全文索引列名

  exec sp_fulltext_column 'titles', 'title', 'add'
  go
  exec sp_fulltext_column 'titles', 'notes', 'add'
  go

  --建立全文索引

  exec sp_fulltext_table 'titles', 'activate'
  go

  --填充全文索引目录

  exec sp_fulltext_catalog 'ft_titles', 'start_full'
  go

  --使用contains和freetext

  select title, notes from titles
  where contains(title, '"computer Cooking"')
  go
  select title, notes from titles
  where freetext(title, 'computer Cooking')
  go
  select title, notes from titles
  where freetext(title, '"computer Cooking"')
  go
  select title, notes from titles
  where contains(title, 'computer')
  go
  select title, notes from titles
  where freetext (*, 'computer')
  go

q里提一下google的搜索引擎的原理.
他把每个字词都做为单元去查询.
打个比方:我在字典里查?现在我要搜烦(ch)"?wi)?q个?他会(x)把这个树(wi)型这个词全文扫描一
?生成一个二叉树(wi).q记下他的页?
然后当我W?ơ查扄时候显然这?记忆"提示,然后"提取".如果你对某一个字D做?jin)全?br />索引的话Q他?x)全文扫描表一?然后U录?
相应的纪?生成二叉?
如果我要查找"?wi)?,同理也可以得出页?但当我们L找一??wi)型l构"他则?x)??wi)?br />"??wi)型l构"?U录"下来.

?巧妙的用烦(ch)?
SELECT SUM(quantity) AS quantity FROM test WHERE...
1.若WHERE 里用的是字段与常量比较,MSSQL?x)自动引用该字段上的索引Q若用的是变量,
MSSQL不会(x)自动引用该字D上的烦(ch)引而是Ҏ(gu)聚集索引q行扫描
2.加上with(index(索引?)指定索引Q即Q?
SELECT SUM(quantity) AS quantity FROM with(index(索引?) test WHERE...
指定索引后,W(xu)HERE 里不论是帔Rq是变量QMSSQL都根据指定的索引q行扫描
3.DBCC DBREINDEX执行q不一定能优化MSSQL性能Q慎?
4.如果在pub_id上徏立烦(ch)引的?
select * from titles where pub_id-500 >1000   ---------(a)
select * from titles where pub_id >1000+500  -----------(b)
请选用(b)语句,q样的话Q他?x)利用?ch)??a)的话׃对字D|作了(jin),所以不?x)利用?ch)?br />.
5.量避免用like语句,
如果L找baa%,caa%的话
如果是like '%aa%','_aa%','[m-z]o%'  则根本不?x)用到?ch)?
替换Ҏ(gu).columns like 'baa%' or  columns like 'caa %'
6什么情况下应不建或徏索引
a.表记录太?.因ؓ(f)索引的话Q要Ҏ(gu)据库往q?ơ操?如果1个表只有几行字段的话Q数
据库?x)对他的U录一ơ性全部取出来,q样的效率要q远高于索引.
b.l常insert,delete,update的表  对一些经常处理的业务表应在查询允许的情况下尽?br />减少索引
c.数据重复且分布^均的表字D??性别字段,各占50%的话Q你即Z(jin),也v不到明显?br />作用.
d.l常和主字段一块查询但dD늃(ch)引值比较多的表字段
表经常按收费序号、户标识~号、抄表日期、电(sh)费发生年月、操作标志来具体查询某一W?br />收款的情况,如果所有的字段都徏在一个烦(ch)引里那将?x)增加数据的修改、插入、删除时
_(d)从实际上分析一W收Ƒ֦果按收费序号索引已l将记录减少到只有几条,如果再按
后面的几个字D늃(ch)引查询将Ҏ(gu)能不生太大的影响?
e.如果一个表的记录达?00万以上的话,要对其中一个字D徏索引可能要花很长的时_(d)
甚至D服务器数据库LQ因为在建烦(ch)引的时?ORACLE要将索引字段所有的内容取出q?br />q行全面排序Q数据量大的话可能导致服务器排序内存不而引用磁盘交换空间进行,q?br />严重媄(jing)响服务器数据库的工作。解x法是增大数据库启动初始化中的排序内存参数Q?br />如果要进行大量的索引修改可以讄10M以上的排序内存(ORACLE~省大小?4KQ,在烦(ch)
引徏立完成后应将参数修改回来Q因为在实际OLTP数据库应用中一般不?x)用到这么大的?br />序内存?


以下转蝲
great_domino ?Blog

探讨如何在有着1000万条数据的MS SQL SERVER数据库中实现快速的数据提取和数据分c(din)?br />以下代码说明?jin)我们实例中数据库的“红头文件”一表的部分数据l构Q?

CREATE TABLE [dbo].[TGongwen] (    --TGongwen是红头文件表?

  [Gid] [int] IDENTITY (1, 1) NOT NULL ,
--本表的idP也是主键

  [title] [varchar] (80) COLLATE Chinese_PRC_CI_AS NULL ,
--U头文g的标?

  [fariqi] [datetime] NULL ,
--发布日期

  [neibuYonghu] [varchar] (70) COLLATE Chinese_PRC_CI_AS NULL ,
--发布用户

  [reader] [varchar] (900) COLLATE Chinese_PRC_CI_AS NULL ,

--需要浏览的用户。每个用户中间用分隔W?”分开

) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO


  下面Q我们来往数据库中d1000万条数据Q?

declare @i int

set @i=1

while @i<=250000

begin

   insert into Tgongwen(fariqi,neibuyonghu,reader,title) values('2004-2-5','?br />信科','通信U?办公?王局?刘局?张局?admin,刑侦支队,特勤支队,交E警支?l?br />侦支? hU?d支队,外事U?,'q是最先的25万条记录')

   set @i=@i+1

end

GO



declare @i int

set @i=1

while @i<=250000

begin

   insert into Tgongwen(fariqi,neibuyonghu,reader,title) values('2004-9-16','?br />公室','办公?通信U?王局?刘局?张局?admin,刑侦支队,特勤支队,交E警支?l?br />侦支?hU?外事U?,'q是中间?5万条记录')

   set @i=@i+1

end

GO



declare @h int

set @h=1

while @h<=100

begin

declare @i int

set @i=2002

while @i<=2003

begin

declare @j int

       set @j=0

       while @j<50

           begin

declare @k int

           set @k=0

           while @k<50

           begin

   insert into Tgongwen(fariqi,neibuyonghu,reader,title) values(cast(@i as var
char(4))+'-8-15 3:'+cast(@j as varchar(2))+':'+cast(@j as varchar(2)),'通信U?
,'办公?通信U?王局?刘局?张局?admin,刑侦支队,特勤支队,交E警支?l侦?br />?hU?外事U?,'q是最后的50万条记录')

           set @k=@k+1

           end

set @j=@j+1

       end

set @i=@i+1

end

set @h=@h+1

end

GO



declare @i int

set @i=1

while @i<=9000000

begin

   insert into Tgongwen(fariqi,neibuyonghu,reader,title) values('2004-5-5','?br />信科','通信U?办公?王局?刘局?张局?admin,刑侦支队,特勤支队,交E警支?l?br />侦支? hU?d支队,外事U?,'q是最后添加的900万条记录')

   set @i=@i+1000000

end

GO

通过以上语句Q我们创Z(jin)25万条׃2004q??日发布的记录Q?5万条由办公室?004
q??日发布的记录Q?002q和2003q各 100?500条相同日期、不同分U的记录Q共50
万条Q,q有由通信U于2004q??日发布的900万条记录Q合?000万条?

何时使用聚集索引或非聚集索引

  下面的表ȝ?jin)何时用聚集?ch)引或非聚集烦(ch)引(很重要)(j)?

  动作描述
   使用聚集索引
   使用非聚集烦(ch)?

  列经常被分组排序
   ?
   ?

  q回某范围内的数?
   ?
   不应

  一个或极少不同?
   不应
   不应

  数目的不同?
   ?
   不应

  大数目的不同?
   不应
   ?

  频繁更新的列
   不应
   ?

  外键?
   ?
   ?

  主键?
   ?
   ?

  频繁修改索引?
   不应
   ?


  事实上,我们可以通过前面聚集索引和非聚集索引的定义的例子来理解上表。如Q返
回某范围内的数据一V比如?zhn)的某个表有一个时间列Q恰好?zhn)把聚合?ch)引徏立在?jin)该?br />Q这时?zhn)查?004q??日至2004q?0?日之间的全部数据Ӟq个速度将是很快的Q?br />因ؓ(f)(zhn)的q本字典正文是按日期q行排序的,聚类索引只需要找到要(g)索的所有数据中?br />开头和l尾数据卛_Q而不像非聚集索引Q必d查到目录中查到每一Ҏ(gu)据对应的늠
Q然后再Ҏ(gu)늠查到具体内容?

Q三Q结合实际,谈烦(ch)引用的误区

  理论的目的是应用。虽然我们刚才列Z(jin)何时应用聚集烦(ch)引或非聚集烦(ch)引,但在?br />践中以上规则却很Ҏ(gu)被忽视或不能Ҏ(gu)实际情况q行l合分析。下面我们将Ҏ(gu)在实?br />中遇到的实际问题来谈一下烦(ch)引用的误区Q以便于大家掌握索引建立的方法?

  1、主键就是聚集烦(ch)?

  q种xW者认为是极端错误的,是对聚集索引的一U浪贏V虽然SQL SERVER默认?br />在主键上建立聚集索引的?

  通常Q我们会(x)在每个表中都建立一个ID列,以区分每条数据,q且q个ID列是自动?br />大的Q步长一般ؓ(f)1。我们的q个办公自动化的实例中的?Gid是如此。此Ӟ如果我们
这个列设ؓ(f)主键QSQL SERVER?x)将此列默认集?ch)引。这样做有好处,是可以让?zhn)?br />的数据在数据库中按照IDq行物理排序Q但W者认样做意义不大?

  显而易见,聚集索引的优势是很明昄Q而每个表中只能有一个聚集烦(ch)引的规则Q这
使得聚集索引变得更加珍贵?

  从我们前面谈到的聚集索引的定义我们可以看出,使用聚集索引的最大好处就是能?br />Ҏ(gu)查询要求Q迅速羃?yu)查询范_(d)避免全表扫描。在实际应用中,因ؓ(f)IDh自动生成
的,我们q不知道每条记录的IDP所以我们很隑֜实践中用IDhq行查询。这׃?br />ID可个主键作集烦(ch)引成ZU资源浪贏V其ơ,让每个ID号都不同的字D作?br />索引也不W合“大数目的不同值情况下不应建立聚合索引”规则;当然Q这U情况只是针
对用L(fng)怿改记录内容,特别是烦(ch)引项的时候会(x)负作用,但对于查询速度q没有媄(jing)响?br />

  在办公自动化pȝ中,无论是系l首|C的需要用L(fng)收的文g、会(x)议还是用戯
行文件查询等M情况下进行数据查询都M开字段的是“日期”还有用hw的“用?br />名”?

  通常Q办公自动化的首会(x)昄每个用户未{收的文件或?x)议。虽然我们的where?br />句可以仅仅限制当前用户尚未签收的情况Q但如果(zhn)的pȝ已徏立了(jin)很长旉Qƈ且数?br />量很大,那么Q每ơ每个用h开首页的时候都q行一ơ全表扫描,q样做意义是不大?br />Q绝大多数的用户1个月前的文g都已l浏览过?jin),q样做只能徒增数据库的开销而已。事
实上Q我们完全可以让用户打开pȝ首页Ӟ数据库仅仅查询这个用戯3个月来未阅览?br />文gQ通过“日期”这个字D|限制表扫描,提高查询速度。如果?zhn)的办公自动化pȝ?br />l徏立的2q_(d)那么(zhn)的首页昄速度理论上将是原来速度8倍,甚至更快?

  在这里之所以提到“理Z”三字,是因为如果?zhn)的聚集?ch)引还是盲目地建在IDq个
主键上时Q?zhn)的查询速度是没有这么高的,即(zhn)在“日期”这个字D上建立的烦(ch)引(?br />聚合索引Q。下面我们就来看一下在1000万条数据量的情况下各U查询的速度表现Q?个月
内的数据?5万条Q:(x)

  Q?Q仅在主键上建立聚集索引Qƈ且不划分旉D:(x)

Select gid,fariqi,neibuyonghu,title from tgongwen

  用时Q?28470毫秒Q即Q?28U)(j)

  Q?Q在主键上徏立聚集烦(ch)引,在fariq上徏立非聚集索引Q?

select gid,fariqi,neibuyonghu,title from Tgongwen

where fariqi> dateadd(day,-90,getdate())

  用时Q?3763毫秒Q?4U)(j)

  Q?Q将聚合索引建立在日期列QfariqiQ上Q?

select gid,fariqi,neibuyonghu,title from Tgongwen

where fariqi> dateadd(day,-90,getdate())

  用时Q?423毫秒Q?U)(j)

  虽然每条语句提取出来的都?5万条数据Q各U情늚差异却是巨大的,特别是将?br />集烦(ch)引徏立在日期列时的差异。事实上Q如果?zhn)的数据库真的?1000万容量的话,把主?br />建立在ID列上Q就像以上的W??U情况,在网上的表现就是超ӞҎ(gu)无法显C?br />q也是我摒弃ID列作集烦(ch)引的一个最重要的因素?

  得出以上速度的方法是Q在各个select语句前加Qdeclare @d datetime

set @d=getdate()

q在select语句后加Q?

select [语句执行p旉(毫秒)]=datediff(ms,@d,getdate())

  2、只要徏立烦(ch)引就能显著提高查询速度

  事实上,我们可以发现上面的例子中Q第2?条语句完全相同,且徏立烦(ch)引的字段?br />相同Q不同的仅是前者在fariqi字段上徏立的是非聚合索引Q后者在此字D上建立的是?br />合烦(ch)引,但查询速度却有着天壤之别。所以,q是在M字段上简单地建立索引p?br />高查询速度?

  从徏表的语句中,我们可以看到q个有着1000万数据的表中fariqi字段?003个不?br />记录。在此字D上建立聚合索引是再合适不q了(jin)。在现实中,我们每天都会(x)发几个文Ӟ
q几个文件的发文日期q同,q完全符合徏立聚集烦(ch)引要求的Q“既不能l大多数都相
同,又不能只有极数相同”的规则。由此看来,我们建立“适当”的聚合索引对于我们
提高查询速度是非帔R要的?

  3、把所有需要提高查询速度的字D都加进聚集索引Q以提高查询速度

  上面已经谈到Q在q行数据查询旉M开字段的是“日期”还有用hw的“用?br />名”。既然这两个字段都是如此的重要,我们可以把他们合qv来,建立一个复合烦(ch)引(
compound indexQ?

  很多为只要把M字段加进聚集索引Q就能提高查询速度Q也有h感到qhQ如
果把复合的聚集烦(ch)引字D分开查询Q那么查询速度?x)减慢吗Q带着q个问题Q我们来看一
下以下的查询速度Q结果集都是25万条数据Q:(x)Q日期列fariqi首先排在复合聚集索引?br />起始列,用户名neibuyonghu排在后列Q?

  Q?Qselect gid,fariqi,neibuyonghu,title from Tgongwen where fariqi>'2004-
5-5'

  查询速度Q?513毫秒

  Q?Qselect gid,fariqi,neibuyonghu,title from Tgongwen where fariqi>'2004-
5-5' and neibuyonghu='办公?

  查询速度Q?516毫秒

  Q?Qselect gid,fariqi,neibuyonghu,title from Tgongwen where neibuyonghu='
办公?

  查询速度Q?0280毫秒

  从以上试验中Q我们可以看到如果仅用聚集烦(ch)引的起始列作为查询条件和同时用到?br />合聚集烦(ch)引的全部列的查询速度是几乎一L(fng)Q甚x用上全部的复合烦(ch)引列q要略快Q?br />在查询结果集数目一L(fng)情况下)(j)Q而如果仅用复合聚集烦(ch)引的非v始列作ؓ(f)查询条g?br />话,q个索引是不起Q何作用的。当?dng)语??的查询速度一h因ؓ(f)查询的条目数一
P如果复合索引的所有列都用上,而且查询l果的话,q样׃(x)形成“烦(ch)引覆盖”,
因而性能可以辑ֈ最优。同Ӟ误住:(x)无论(zhn)是否经怋用聚合烦(ch)引的其他列,但其?br />导列一定要是用最频繁的列?

Q四Q其他书上没有的索引使用l验ȝ

  1、用聚合索引比用不是聚合索引的主键速度?

  下面是实例语句:(x)Q都是提?5万条数据Q?

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-
16'

  使用旉Q?326毫秒

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where gid<=250000

  使用旉Q?470毫秒

  q里Q用聚合索引比用不是聚合索引的主键速度快了(jin)q?/4?

  2、用聚合索引比用一般的主键作order by旉度快,特别是在数据量情况?

select gid,fariqi,neibuyonghu,reader,title from Tgongwen order by fariqi

  用时Q?2936

select gid,fariqi,neibuyonghu,reader,title from Tgongwen order by gid

  用时Q?8843

  q里Q用聚合索引比用一般的主键作order byӞ速度快了(jin)3/10。事实上Q如果数?br />量很的话,用聚集烦(ch)引作为排序列要比使用非聚集烦(ch)引速度快得明显的多Q而数据量?br />果很大的话,?0万以上,则二者的速度差别不明显?

  3、用聚合烦(ch)引内的时间段Q搜索时间会(x)按数据占整个数据表的癑ֈ比成比例减少Q?br />而无合烦(ch)引用了(jin)多少?

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>'2004-1-
1'

  用时Q?343毫秒Q提?00万条Q?

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>'2004-6-
6'

  用时Q?170毫秒Q提?0万条Q?

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-
16'

  用时Q?326毫秒Q和上句的结果一模一栗如果采集的数量一P那么用大于号和等
于号是一L(fng)Q?

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>'2004-1-
1' and fariqi<'2004-6-6'

  用时Q?280毫秒

  4 、日期列不会(x)因ؓ(f)有分U的输入而减慢查询速度

  下面的例子中Q共?00万条数据Q?004q??日以后的数据?0万条Q但只有两个?br />同的日期Q日期精到日;之前有数?0万条Q有5000个不同的日期Q日期精到U?


select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>'2004-1-
1' order by fariqi

  用时Q?390毫秒

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi<'2004-1-
1' order by fariqi

  用时Q?453毫秒

  Q五Q其他注意事?

  “水可蝲舟,亦可覆舟”,索引也一栗烦(ch)引有助于提高?gu)(g)索性能Q但q多或不当的
索引也会(x)Dpȝ低效。因为用户在表中每加q一个烦(ch)引,数据库就要做更多的工作。过
多的索引甚至?x)导致?ch)引碎片?

  所以说Q我们要建立一个“适当”的索引体系Q特别是对聚合烦(ch)引的创徏Q更应精?br />求精Q以使?zhn)的数据库能得到高性能的发挥?

  当然Q在实践中,作ؓ(f)一个尽职的数据库管理员Q?zhn)q要多测试一些方案,扑և哪种
Ҏ(gu)效率最高、最为有效?

二、改善SQL语句

  很多Z知道SQL语句在SQL SERVER中是如何执行的,他们担心(j)自己所写的SQL语句?br />被SQL SERVER误解。比如:(x)

select * from table1 where name='zhangsan' and tID > 10000

  和执?

select * from table1 where tID > 10000 and name='zhangsan'

  一些h不知道以上两条语句的执行效率是否一P因ؓ(f)如果单的从语句先后上看,
q两个语句的是不一P如果tID是一个聚合烦(ch)引,那么后一句仅仅从表的10000条以?br />的记录中查找p?jin);而前一句则要先从全表中查找看有几个name='zhangsan'的,而后?br />Ҏ(gu)限制条g条g tID>10000来提出查询结果?

  事实上,q样的担?j)是不必要的。SQL SERVER中有一个“查询分析优化器”,它可?br />计算出where子句中的搜烦(ch)条gq确定哪个烦(ch)引能~小表扫描的搜烦(ch)I间Q也是_(d)它能
实现自动优化?

  虽然查询优化器可以根据where子句自动的进行查询优化,但大家仍然有必要?jin)解一?br />“查询优化器”的工作原理Q如非这P有时查询优化器就?x)不按照?zhn)的本意q行快速查
询?

  在查询分析阶D,查询优化器查看查询的每个阶段q决定限刉要扫描的数据量是?br />有用。如果一个阶D可以被用作一个扫描参敎ͼSARGQ,那么q之ؓ(f)可优化的Qƈ且可
以利用烦(ch)引快速获得所需数据?

  SARG的定义:(x)用于限制搜烦(ch)的一个操作,因ؓ(f)它通常是指一个特定的匚wQ一个值得
范围内的匚w或者两个以上条件的ANDq接。Ş式如下:(x)

列名 操作W?<常数 ?变量>

?

<常数 ?变量> 操作W列?

  列名可以出现在操作符的一边,而常数或变量出现在操作符的另一辏V如Q?

Name=’张三?

h>5000

5000<h

Name=’张三?and h>5000

  如果一个表辑ּ不能满SARG的Ş式,那它?yu)无法限制搜索的范围了(jin),也就是SQL SE
RVER必须Ҏ(gu)一行都判断它是否满WHERE子句中的所有条件。所以一个烦(ch)引对于不满S
ARG形式的表辑ּ来说是无用的?

  介绍完SARG后,我们来ȝ一下用SARG以及(qing)在实践中遇到的和某些资料上结Z?br />的经验:(x)

  1、Like语句是否属于SARG取决于所使用的通配W的cd

  如:(x)name like ‘张%?Q这属于SARG

  而:(x)name like ?张?,׃属于SARG?

  原因是通配W?在字W串的开通得烦(ch)引无法用?

  2、or ?x)引起全表扫?

Name=’张三?and h>5000 W号SARGQ而:(x)Name=’张三?or h>5000 则不W合S
ARG。用or?x)引起全表扫描?

  3、非操作W、函数引L(fng)不满SARG形式的语?

  不满SARG形式的语句最典型的情况就是包括非操作W的语句Q如QNOT?=?lt;>?
<?>、NOT EXISTS、NOT IN、NOT LIKE{,另外q有函数。下面就是几个不满SARG形式
的例子:(x)

ABS(h)<5000

Name like ?三?

  有些表达式,如:(x)

WHERE h*2>5000

  SQL SERVER也会(x)认ؓ(f)是SARGQSQL SERVER?x)将此式转化为?x)

WHERE h>2500/2

  但我们不推荐q样使用Q因为有时SQL SERVER不能保证q种转化与原始表辑ּ是完?br />{h(hun)的?

  4、IN 的作用相当与OR

  语句Q?

Select * from table1 where tid in (2,3)

  ?

Select * from table1 where tid=2 or tid=3

  是一L(fng)Q都?x)引起全表扫描,如果tid上有索引Q其索引也会(x)失效?

  5、尽量少用NOT

  6、exists ?in 的执行效率是一L(fng)

  很多资料上都昄_(d)exists要比in的执行效率要高,同时应尽可能的用not exists
来代替not in。但事实上,我试验了(jin)一下,发现二者无论是前面带不带notQ二者之间的?br />行效率都是一L(fng)。因为涉?qing)子查询Q我们试验这ơ用SQL SERVER自带的pubs数据库。运
行前我们可以把SQL SERVER的statistics I/O状态打开?

  Q?Qselect title,price from titles where title_id in (select title_id fro
m sales where qty>30)

  该句的执行结果ؓ(f)Q?

  ?'sales'。扫描计?18Q逻辑?56 ơ,物理?0 ơ,预读 0 ơ?

  ?'titles'。扫描计?1Q逻辑?2 ơ,物理?0 ơ,预读 0 ơ?

  Q?Qselect title,price from titles where exists (select * from sales wher
e sales.title_id=titles.title_id and qty>30)

  W二句的执行l果为:(x)

  ?'sales'。扫描计?18Q逻辑?56 ơ,物理?0 ơ,预读 0 ơ?

  ?'titles'。扫描计?1Q逻辑?2 ơ,物理?0 ơ,预读 0 ơ?

  我们从此可以看到用exists和用in的执行效率是一L(fng)?

  7、用函数charindex()和前面加通配W?的LIKE执行效率一?

  前面Q我们谈刎ͼ如果在LIKE前面加上通配W?Q那么将?x)引起全表扫描,所以其执行
效率是低下的。但有的资料介绍_(d)用函数charindex()来代替LIKE速度?x)有大的提升Q经
我试验,发现q种说明也是错误的:(x)

select gid,title,fariqi,reader from tgongwen where charindex('刑侦支队',reader
)>0 and fariqi>'2004-5-5'

  用时Q?U,另外Q扫描计?4Q逻辑?7155 ơ,物理?0 ơ,预读 0 ơ?

select gid,title,fariqi,reader from tgongwen where reader like '%' + '刑侦支队
' + '%' and fariqi>'2004-5-5'

  用时Q?U,另外Q扫描计?4Q逻辑?7155 ơ,物理?0 ơ,预读 0 ơ?

  8、unionq不l对比or的执行效率高

  我们前面已经谈到?jin)在where子句中用or?x)引起全表扫描,一般的Q我所见过的资?br />都是推荐q里用union来代替or。事实证明,q种说法对于大部分都是适用的?

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-
16' or gid>9990000

  用时Q?8U。扫描计?1Q逻辑?404008 ơ,物理?283 ơ,预读 392163 ơ?


select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-
16'

union

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where gid>9990000

  用时Q?U。扫描计?8Q逻辑?67489 ơ,物理?216 ơ,预读 7499 ơ?

  看来Q用union在通常情况下比用or的效率要高的多?

  但经q试验,W者发现如果or两边的查询列是一L(fng)话,那么用union则反倒和用or?br />执行速度差很多,虽然q里union扫描的是索引Q而or扫描的是全表?

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-
16' or fariqi='2004-2-5'

  用时Q?423毫秒。扫描计?2Q逻辑?14726 ơ,物理?1 ơ,预读 7176 ơ?


select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-
16'

union

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where  fariqi='2004-2
-5'

  用时Q?1640毫秒。扫描计?8Q逻辑?14806 ơ,物理?108 ơ,预读 1144 ơ?br />

  9、字D|取要按照“需多少、提多少”的原则Q避免“select *?

  我们来做一个试验:(x)

select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc

  用时Q?673毫秒

select top 10000 gid,fariqi,title from tgongwen order by gid desc

  用时Q?376毫秒

select top 10000 gid,fariqi from tgongwen order by gid desc

  用时Q?0毫秒

  由此看来Q我们每提取一个字D,数据的提取速度׃(x)有相应的提升。提升的速度
q要看?zhn)舍弃的字D늚大小来判断?

  10、count(*)不比count(字段)?

  某些资料上说Q用*?x)统计所有列Q显然要比一个世界的列名效率低。这U说法其实是
没有Ҏ(gu)的。我们来看:(x)

select count(*) from Tgongwen

  用时Q?500毫秒

select count(gid) from Tgongwen

  用时Q?483毫秒

select count(fariqi) from Tgongwen

  用时Q?140毫秒

select count(title) from Tgongwen

  用时Q?2050毫秒

  从以上可以看出,如果用count(*)和用count(主键)的速度是相当的Q而count(*)却比
其他M除主键以外的字段汇总速度要快Q而且字段长Q汇ȝ速度p慢。我惻I?br />果用count(*)Q?SQL SERVER可能?x)自动查找最字D|汇ȝ。当?dng)如果?zhn)直接写cou
nt(主键)会(x)来的更直接些?

  11、order by按聚集烦(ch)引列排序效率最?

  我们来看Q(gid是主键,fariqi是聚合烦(ch)引列Q?

select top 10000 gid,fariqi,reader,title from tgongwen

  用时Q?96 毫秒?扫描计数 1Q逻辑?289 ơ,物理?1 ơ,预读 1527 ơ?

select top 10000 gid,fariqi,reader,title from tgongwen order by gid asc

  用时Q?720毫秒?扫描计数 1Q逻辑?41956 ơ,物理?0 ơ,预读 1287 ơ?


select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc

  用时Q?736毫秒?扫描计数 1Q逻辑?55350 ơ,物理?10 ơ,预读 775 ơ?


select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi asc

  用时Q?73毫秒?扫描计数 1Q逻辑?290 ơ,物理?0 ơ,预读 0 ơ?

select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi desc

  用时Q?56毫秒?扫描计数 1Q逻辑?289 ơ,物理?0 ơ,预读 0 ơ?

  从以上我们可以看出,不排序的速度以及(qing)逻辑L数都是和“order by 聚集索引列?br /> 的速度是相当的Q但q些都比“order by 非聚集烦(ch)引列”的查询速度是快得多的?

  同时Q按照某个字D进行排序的时候,无论是正序还是倒序Q速度是基本相当的?


  12、高效的TOP

  事实上,在查询和提取大定w的数据集Ӟ影响数据库响应时间的最大因素不是数
据查找,而是物理的I/0操作。如Q?

select top 10 * from (

select top 10000 gid,fariqi,title from tgongwen

where neibuyonghu='办公?

order by gid desc) as a

order by gid asc

  q条语句Q从理论上讲Q整条语句的执行旉应该比子句的执行旉长,但事实相?br />。因为,子句执行后返回的?0000条记录,而整条语句仅q回 10条语句,所以媄(jing)响数?br />库响应时间最大的因素是物理I/O操作。而限制物理I/O操作此处的最有效Ҏ(gu)之一是?br />用TOP关键词了(jin)。TOP关键词是 SQL SERVER中经q系l优化过的一个用来提取前几条或前?br />个百分比数据的词。经W者在实践中的应用Q发现TOP实很好用,效率也很高。但q个?br />在另外一个大型数据库ORACLE中却没有Q这不能说不是一个遗憾,虽然在ORACLE中可以用
其他Ҏ(gu)Q如QrownumberQ来解决。在以后的关于“实现千万数据的分|C存储过E?br />”的讨论中,我们将用到TOPq个关键词?

  到此为止Q我们上面讨Z(jin)如何实现从大定w的数据库中快速地查询出?zhn)所需要的?br />据方法。当?dng)我们介绍的这些方法都是“Y”方法,在实践中Q我们还要考虑各种“硬
”因素,如:(x)|络性能、服务器的性能、操作系l的性能Q甚至网卡、交换机{?

三、实现小数据量和量数据的通用分页昄存储q程

  建立一个web 应用Q分|览功能必不可。这个问题是数据库处理中十分常见的问
题。经典的数据分页Ҏ(gu)?ADO U录集分|Q也是利用ADO自带的分功能(利用?br />标)(j)来实现分c(din)但q种分页Ҏ(gu)仅适用于较?yu)数据量的情形,因?f)游标本n有缺点:(x)?br />标是存放在内存中Q很费内存。游标一建立Q就相关的记录锁住Q直到取消游标。游?br />提供?jin)对特定集合中逐行扫描的手D,一般用游标来逐行遍历数据Q根据取出数据条?br />的不同进行不同的操作。而对于多表和大表中定义的游标Q大的数据集合)(j)循环很容易
E序q入一个O长的{待甚至L?

  更重要的是,对于非常大的数据模型而言Q分|索时Q如果按照传l的每次都加?br />整个数据源的Ҏ(gu)是非常浪费资源的。现在流行的分页Ҏ(gu)一般是(g)索页面大的块区?br />数据Q而非(g)索所有的数据Q然后单步执行当前行?

  最早较好地实现q种Ҏ(gu)面大小和页码来提取数据的方法大概就是“俄|斯存储q?br />E”。这个存储过E用?jin)游标,׃游标的局限性,所以这个方法ƈ没有得到大家的普?br />认可?

  后来Q网上有人改造了(jin)此存储过E,下面的存储过E就是结合我们的办公自动化实?br />写的分页存储q程Q?

CREATE procedure pagination1

(@pagesize int,  --面大小Q如每页存储20条记?

@pageindex int   --当前늠

)

as

set nocount on

begin

declare @indextable table(id int identity(1,1),nid int)  --定义表变?

declare @PageLowerBound int  --定义此页的底?

declare @PageUpperBound int  --定义此页的顶?

set @PageLowerBound=(@pageindex-1)*@pagesize

set @PageUpperBound=@PageLowerBound+@pagesize

set rowcount @PageUpperBound

insert into @indextable(nid) select gid from TGongwen where fariqi >dateadd(da
y,-365,getdate()) order by fariqi desc

select O.gid,O.mid,O.title,O.fadanwei,O.fariqi from TGongwen O,@indextable t w
here O.gid=t.nid

and t.id>@PageLowerBound and t.id<=@PageUpperBound order by t.id

end

set nocount off

  以上存储q程q用?jin)SQL SERVER的最新技术――表变量。应该说q个存储q程也是一
个非怼U的分存储过E。当?dng)在这个过E中Q?zhn)也可以把其中的表变量写成临时?br />Q?CREATE TABLE #Temp。但很明显,在SQL SERVER中,用(f)时表是没有用表变量快的。所
以笔者刚开始用这个存储过E时Q感觉非常的不错Q速度也比原来的ADO的好。但后来Q?br />我又发现?jin)比此方法更好的?gu)?

  W者曾在网上看C(jin)一小短文《从数据表中取出Wn条到Wm条的记录的方法》,?br />文如下:(x)

从publish 表中取出W?n 条到W?m 条的记录Q?
SELECT TOP m-n+1 *
FROM publish
WHERE (id NOT IN
    (SELECT TOP n-1 id
     FROM publish))

id 为publish 表的关键?

  我当时看到这文章的时候,真的是精ؓ(f)之一振,觉得思\非常得好。等到后来,
我在作办公自动化pȝQASP.NET+ C#QSQL SERVERQ的时候,忽然惌v?jin)这文章,我?br />如果把这个语句改造一下,q就可能是一个非常好的分存储过E。于是我满|上找这
文章,没想刎ͼ文章q没扑ֈQ却扑ֈ?jin)一根据此语句写的一个分存储过E,q个
存储q程也是目前较ؓ(f)行的一U分存储过E,我很后?zhn)没有争先把这D|字改造成?br />储过E:(x)

CREATE PROCEDURE pagination2
(
@SQL nVARCHAR(4000),    --不带排序语句的SQL语句
@Page int,              --늠
@RecsPerPage int,       --每页容纳的记录数
@ID VARCHAR(255),       --需要排序的不重复的ID?
@Sort VARCHAR(255)      --排序字段?qing)规?
)
AS

DECLARE @Str nVARCHAR(4000)

SET @Str='SELECT   TOP '+CAST(@RecsPerPage AS VARCHAR(20))+' * FROM ('+@SQL+')
T WHERE T.'+@ID+'NOT IN
(SELECT   TOP '+CAST((@RecsPerPage*(@Page-1)) AS VARCHAR(20))+' '+@ID+' FROM (
'+@SQL+') T9 ORDER BY '+@Sort+') ORDER BY '+@Sort

PRINT @Str

EXEC sp_ExecuteSql @Str
GO

  其实Q以上语句可以简化ؓ(f)Q?

SELECT TOP 大?*

FROM Table1

WHERE (ID NOT IN

         (SELECT TOP 大?| id

        FROM ?

        ORDER BY id))

ORDER BY ID

  但这个存储过E有一个致命的~点Q就是它含有NOT IN字样。虽然我可以把它攚wؓ(f)
Q?

SELECT TOP 大?*

FROM Table1

WHERE not exists

(select * from (select top (大?|) * from table1 order by id) b where b.
id=a.id )

order by id

  卻I用not exists来代替not inQ但我们前面已经谈过?jin),二者的执行效率实际上是
没有区别的?

  既便如此Q用TOP l合NOT IN的这个方法还是比用游标要来得快一些?

  虽然用not existsq不能挽救上个存储过E的效率Q但使用SQL SERVER中的TOP关键?br />却是一个非常明智的选择。因为分优化的最l目的就是避免生过大的记录集,而我?br />在前面也已经提到?jin)TOP的优势,通过TOP 卛_实现Ҏ(gu)据量的控制?

  在分늮法中Q媄(jing)响我们查询速度的关键因素有两点QTOP和NOT IN。TOP可以提高?br />们的查询速度Q而NOT IN?x)减慢我们的查询速度Q所以要提高我们整个分页法的速度Q?br />pd攚wNOT INQ同其他Ҏ(gu)来替代它?

  我们知道Q几乎Q何字D,我们都可以通过max(字段)或min(字段)来提取某个字D中
的最大或最|所以如果这个字D不重复Q那么就可以利用q些不重复的字段的max或m
in作ؓ(f)分水岭,使其成ؓ(f)分页法中分开每页的参照物。在q里Q我们可以用操作W?gt;?br />或?lt;”号来完成这个命,使查询语句符合SARG形式。如Q?

Select top 10 * from table1 where id>200

  于是有?jin)如下分|案:(x)

select top 大?*

from table1

where id>

     (select max (id) from

     (select top ((늠-1)*大? id from table1 order by id) as T

      )    

order by id

  在选择即不重复|又容易分辨大的列时Q我们通常?x)选择主键。下表列Z(jin)W?br />用有着1000万数据的办公自动化系l中的表Q在以GID QGID是主键,但ƈ不是聚集索引?br />Qؓ(f)排序列、提取gid,fariqi,title字段Q分别以W??0?00?00?000?万?0 ?br />?5万?0万页ZQ测试以上三U分|案的执行速度Q(单位Q毫U)(j)

??
Ҏ(gu)1
Ҏ(gu)2
Ҏ(gu)3

1
60
30
76

10
46
16
63

100
1076
720
130

500
540
12943
83

1000
17110
470
250

1?
24796
4500
140

10?
38326
42283
1553

25?
28140
128720
2330

50?
121686
127846
7168


  从上表中Q我们可以看出,三种存储q程在执?00以下的分页命o(h)Ӟ都是可以?br />ȝQ速度都很好。但W一U方案在执行分页1000以上后Q速度降?jin)下来。第二种?br />案大U是在执行分?万页以上后速度开始降?jin)下来。而第三种Ҏ(gu)却始l没有大的降势,
后劲仍然很?

  在确定了(jin)W三U分|案后Q我们可以据此写一个存储过E。大家知道SQL SERVER?br />存储q程是事先编译好的SQL语句Q它的执行效率要比通过WEB面传来的SQL语句的执行效
率要高。下面的存储q程不仅含有分页Ҏ(gu)Q还?x)根据页面传来的参数来确定是否进行?br />据Ll计?

-- 获取指定늚数据

CREATE PROCEDURE pagination3

@tblName   varchar(255),       -- 表名

@strGetFields varchar(1000) = '*',  -- 需要返回的?

@fldName varchar(255)='',      -- 排序的字D名

@PageSize   int = 10,          -- 尺?

@PageIndex  int = 1,           -- 늠

@doCount  bit = 0,   -- q回记录L, ?0 值则q回

@OrderType bit = 0,  -- 讄排序cd, ?0 值则降序

@strWhere  varchar(1500) = ''  -- 查询条g (注意: 不要?where)

AS

declare @strSQL   varchar(5000)       -- 主语?

declare @strTmp   varchar(110)        -- 临时变量

declare @strOrder varchar(400)        -- 排序cd



if @doCount != 0

begin

   if @strWhere !=''

   set @strSQL = "select count(*) as Total from [" + @tblName + "] where "+@st
rWhere

   else

   set @strSQL = "select count(*) as Total from [" + @tblName + "]"

end

--以上代码的意思是如果@doCount传递过来的不是0Q就执行Ll计。以下的所有代码都
是@doCount?的情?

else

begin



if @OrderType != 0

begin

   set @strTmp = "<(select min"

set @strOrder = " order by [" + @fldName +"] desc"

--如果@OrderType不是0Q就执行降序Q这句很重要Q?

end

else

begin

   set @strTmp = ">(select max"

   set @strOrder = " order by [" + @fldName +"] asc"

end



if @PageIndex = 1

begin

   if @strWhere != ''  

   set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ "  from ["
+ @tblName + "] where " + @strWhere + " " + @strOrder

    else

    set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ "  from [
"+ @tblName + "] "+ @strOrder

--如果是第一就执行以上代码Q这样会(x)加快执行速度

end

else

begin

--以下代码赋予?jin)@strSQL以真正执行的SQL代码

set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ "  from ["

   + @tblName + "] where [" + @fldName + "]" + @strTmp + "(["+ @fldName + "])
from (select top " + str((@PageIndex-1)*@PageSize) + " ["+ @fldName + "] from
[" + @tblName + "]" + @strOrder + ") as tblTmp)"+ @strOrder



if @strWhere != ''

   set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ "  from ["


       + @tblName + "] where [" + @fldName + "]" + @strTmp + "(["

       + @fldName + "]) from (select top " + str((@PageIndex-1)*@PageSize) + "
["

       + @fldName + "] from [" + @tblName + "] where " + @strWhere + " "

       + @strOrder + ") as tblTmp) and " + @strWhere + " " + @strOrder

end

end  

exec (@strSQL)

GO

  上面的这个存储过E是一个通用的存储过E,其注释已写在其中?jin)?

  在大数据量的情况下,特别是在查询最后几늚时候,查询旉一般不?x)超q?U;?br />用其他存储过E,在实践中׃(x)D时Q所以这个存储过E非帔R用于大定w数据库的
查询?

  W者希望能够通过对以上存储过E的解析Q能l大家带来一定的启示Qƈl工作带?br />一定的效率提升Q同时希望同行提出更优秀的实时数据分늮法?

四、聚集烦(ch)引的重要性和如何选择聚集索引

  在上一节的标题中,W者写的是Q实现小数据量和量数据的通用分页昄存储q程
。这是因为在本存储q程应用于“办公自动化”系l的实践中时Q笔者发现这W三U存
储过E在数据量的情况下Q有如下现象Q?

  1、分速度一般维持在1U和3U之间?

  2、在查询最后一|Q速度一般ؓ(f)5U至8U,哪怕分|L只有3|30万页?

  虽然在超大容量情况下Q这个分늚实现q程是很快的Q但在分前几|Q这?Q?
U的速度比vW一U甚x有经q优化的分页Ҏ(gu)速度q要慢,借用L(fng)话说是“还?br />有ACCESS数据库速度快”,q个认识以D用户攑ּ使用(zhn)开发的pȝ?

  W者就此分析了(jin)一下,原来产生q种现象的症l是如此的简单,但又如此的重要:(x)?br />序的字段不是聚集索引Q?

  本篇文章的题目是Q“查询优化及(qing)分页法Ҏ(gu)”。笔者只所以把“查询优化”和?br />分页法”这两个联系不是很大的论题放在一P是因ؓ(f)二者都需要一个非帔R要的?br />襎쀕―聚集烦(ch)引?

  在前面的讨论中我们已l提C(jin)Q聚集烦(ch)引有两个最大的优势Q?

  1、以最快的速度~小查询范围?

  2、以最快的速度q行字段排序?

  W?条多用在查询优化Ӟ而第2条多用在q行分页时的数据排序?

  而聚集烦(ch)引在每个表内又只能徏立一个,q得聚集烦(ch)引显得更加的重要。聚集烦(ch)?br />的挑选可以说是实现“查询优化”和“高效分”的最关键因素?

  但要既聚集索引列既W合查询列的需要,又符合排序列的需要,q通常是一个矛?br />?

  W者前面“烦(ch)引”的讨论中,fariqiQ即用户发文日期作ؓ(f)?jin)聚集?ch)引的起始列,
日期的精度为“日”。这U作法的优点Q前面已l提C(jin)Q在q行划时间段的快速查?br />中,比用ID主键列有很大的优ѝ?

  但在分页Ӟ׃q个聚集索引列存在着重复记录Q所以无法用max或min来最为分
늚参照物,q而无法实现更为高效的排序。而如果将ID主键列作集烦(ch)引,那么聚集
索引除了(jin)用以排序之外Q没有Q何用处,实际上是费?jin)聚集?ch)引这个宝늚资源?

   册个矛盾,W者后来又d?jin)一个日期列Q其默认gؓ(f)getdate()。用户在?br />入记录时Q这个列自动写入当时的时_(d)旉_到毫U。即使这PZ(jin)避免可能性很
的重合Q还要在此列上创建UNIQUEU束。将此日期列作ؓ(f)聚集索引列?

  有了(jin)q个旉型聚集烦(ch)引列之后Q用户就既可以用q个列查扄户在插入数据时的?br />个时间段的查询,又可以作为唯一列来实现max或minQ成为分늮法的参照物?

  l过q样的优化,W者发玎ͼ无论是大数据量的情况下还是小数据量的情况下,分页
速度一般都是几十毫U,甚至0毫秒。而用日期D늾?yu)范围的查询速度比原来也没有Mq?br />钝?

  聚集索引是如此的重要和珍贵,所以笔者ȝ?jin)一下,一定要聚集烦(ch)引徏立在Q?


  1、?zhn)最频繁使用的、用以羃?yu)查询范围的字段上?

  2、?zhn)最频繁使用的、需要排序的字段上?

  l束语:(x)

  希望q篇文章不仅能够l大家的工作带来一定的帮助Q也希望能让大家能够体会(x)到分
析问题的Ҏ(gu)Q最重要的是Q希望这文章能够抛砖引玉,掀起大家的学习(fn)和讨论的兴趣
Q以共同?j)进?
  最后需要说明的是,在试验中Q发现用户在q行大数据量查询的时候,Ҏ(gu)据库速度
影响最大的不是内存大小Q而是CPU。在我的P4 2.4机器上试验的时候,查看“资源管理器
”,CPUl常出现持箋?00%的现象,而内存用量却q没有改变或者说没有大的改变。即?br />在我们的HP ML 350 G3服务器上试验ӞCPU峰g能达?0%Q一般持l在70%左右?

  本文的试验数据都是来自我们的HP ML 350服务器。服务器配置Q双Inter Xeon 线
E?CPU 2.4GQ内?GQ操作系lWindows Server 2003 Enterprise EditionQ数据库SQL
Server 2000 SP3?

转蝲完毕.


作者补?
1.columns in('aa','bb')
他等于columns = 'aa' or columns ='bb' 他先L询columns ='aa'攑֜一个(f)时的I间
?然后{columns ='bb'查询完后,做个or查询得出l果.
至于效率的话Q在columns建立索引的话, columns ='aa' or columns ='bb'要来的效率高

语法分析器会(x)columns in('aa','bb')转化
为columns ='aa' or columns ='bb'来执行。我们期望它?x)根据每个or子句分别查找Q再
结?
相加Q这样可以利用columns 上的索引Q但实际上(Ҏ(gu)showplanQ?它却采用?OR{略
"
Q即先取出满x个or子句的行Q存入(f)时数据库的工作表中,再徏立唯一索引以去?

重复行,最后从q个临时表中计算l果。因此,实际q程没有利用columns 上烦(ch)引,q且
?
成时间还要受tempdb数据库性能的媄(jing)响?


2.效率从高C count(1)>count(*)>count([id])

3.select max(cols) from table1 的效?gt;= select top 1 cols from table1 order by
cols desc

4.在where 做ƈ列条件句?where cols1='aa' and cols2='bb'
如果cols1 ='aa' ?5% cols2?%的话Q把cols2='bb'攑֜前面 ,因ؓ(f)他在(g)索cols ='
bb'的时候他只需查那5%,然后条g成立的话Q去在这5%的纪录里
L找cols1 ='aa'

5.避免用if条g?可以用or来替?
declare @vsql varchar(200)
set @vsql ='Renaski'
select * from titles where  @vsql ='Renaski' or price = 11.9500

如果@vsql为Renaski则把所有的U录都选出?如果不是的话Q则只查询price = 11.9500
的纪?

6.M对列的操作都导致表扫描Q它包括数据库函数、计表辑ּ{等Q查询时
要尽可能操作移至等号右辏V?

7.量避免使用游标.
如果使用?jin)游标,p量避免在游标@环中再进行表q接的操?

8.取一个表的纪录数
Select rows from sysindexes where id=object_id(N'titles') and indid<2
效率?
select count(1) from titles来的?


9.取的一个表的数据信?
SELECT
表名=case when a.colorder=1 then d.name else '' end,
表说?case when a.colorder=1 then isnull(f.value,'') else '' end,
字段序号=a.colorder,
字段?a.name,
标识=case when COLUMNPROPERTY( a.id,a.name,'IsIdentity')=1 then '?else '' en
d,
主键=case when exists(SELECT 1 FROM sysobjects where xtype='PK' and name in (

SELECT name FROM sysindexes WHERE indid in(
SELECT indid FROM sysindexkeys WHERE id = a.id AND colid=a.colid
))) then '? else '' end,
cd=b.name,
占用字节?a.length,
长度=COLUMNPROPERTY(a.id,a.name,'PRECISION'),
数位数=isnull(COLUMNPROPERTY(a.id,a.name,'Scale'),0),
允许I?case when a.isnullable=1 then '?else '' end,
默认?isnull(e.text,''),
字段说明=isnull(g.[value],''),
索引名称=isnull(h.索引名称,''),
索引序=isnull(h.排序,'')
FROM syscolumns a
left join systypes b on a.xtype=b.xusertype
inner join sysobjects d on a.id=d.id and d.xtype='U' and d.status>=0
left join syscomments e on a.cdefault=e.id
left join sysproperties g on a.id=g.id and a.colid=g.smallid
left join sysproperties f on d.id=f.id and f.smallid=0
left join(--q部分是索引信息,如果要显C烦(ch)引与表及(qing)字段的对应关p?可以只要此部?br />
select 索引名称=a.name,c.id,d.colid
,排序=case indexkey_property(c.id,b.indid,b.keyno,'isdescending')
when 1 then '降序' when 0 then '升序' end
from sysindexes a
join sysindexkeys b on a.id=b.id and a.indid=b.indid
join (--q里的作用是有多个烦(ch)引时,取烦(ch)引号最的那个
select id,colid,indid=min(indid) from sysindexkeys
group by id,colid) b1 on b.id=b1.id and b.colid=b1.colid and b.indid=b1.indid

join sysobjects c on b.id=c.id and c.xtype='U' and c.status>=0
join syscolumns d on b.id=d.id and b.colid=d.colid
where a.indid not in(0,255)
) h on a.id=h.id and a.colid=h.colid
--where d.name='要查询的? --如果只查询指定表,加上此条?
order by a.id,a.colorder


10.创徏一个表l构.
select * into #b from authors where 1=2;
注意:
#table1
##table1
@table1

局部(f)时表
以一个井P#Q开头的那些表名。只有在创徏本地临时表的q接上才能看到这些表?

全局临时?
以两个井P##Q开头的那些表名。在所有连接上都能看到全局临时表。如果在创徏全局
临时表的q接断开前没有显式地除去q些表,那么只要所有其它Q务停止引用它们,q些
表即被除厅R当创徏全局临时表的q接断开后,新的d不能再引用它们。当前的语句一
执行完,d与表之间的关联即被除去;因此通常情况下,只要创徏全局临时表的q接?br />开Q全局临时表即被除厅R?

@?有和不同Q@@在内存,#在硬盘。我的体?x)是只要方便且数据量不大Q用@@?

11.视图
他只是记住要q接,兌列的信息,他不存放M物理数据.
在调用的时候他q是d各个表中的数?

12.量不要用text属?
pȝZ专门开辟一个空间来存放.
用t-sql/varchar替代
pl/sql  varchar2 替代.

13
GO语句是个命o(h)识别q过osql和isql和SQL 查询分析器非T-SQL语句q行识别?
如果你用查询分析器作ؓ(f)你的d发工P其他语句和库文g不?x)识别GO语句作ؓ(f)一
个T-SQL命o(h)

14.
用exec 效率来的?
declare @sql nvarchar(300)
  set @sql='select * from titles'
execute sp_executesql @sql

15,注意你的tempdb,使他自动增长.

16 使用no_log
select * from titles no_logs

17M重复U录?量用dictinct

18.量避免反复讉K同一张或几张表,其是数据量较大的表Q可以考虑先根据条件提?br />数据C(f)时表中,然后再做q接?


19 量使用?gt;=”,不要使用?gt;”?他会(x)扑ֈ某个定的数字进行筛??gt;则没?


20注意表之间连接的数据cdQ避免不同类型数据之间的q接?

21.可用ASE调优命o(h)Qset statistics io on, set statistics time on , set showpla
n on {?q行优化

22.truncate table 删除数据
而不是delete from table


?死锁

像SQL server一L(fng)关系数据库用锁来防止用户“互相踩到对方的脚趾头”。也是?br />Q锁可以防止用户造成修改数据时的撞。当一个用户锁住一D代码时候,其它的用户都
不能修改q段数据。另外,一个锁L?jin)用戯看未被授权的数据修改。用户必ȝ待到
数据修改q保存之后才能够查看它。数据必M用不同的Ҏ(gu)来加锁。SQL Server 2000?br />用锁来实现多用户同时修改数据库同一数据时的同步控制
如果数据量超q?00个数据页面(400kQ,那么pȝ会(x)q行锁升U,锁会(x)升成表U?br />锁?  


死锁
一个数据库的死锁是发生在两个或多于两个讉K一些资源的数据库会(x)话中的,q且q些?br />话相互之间有依赖关系。死锁是可以在Q意一个多U程的系l成出现的一个情况,不仅?br />局限于关系数据库管理系l。一个多U程pȝ中的U程可能需要一个或多个资源(例如Q锁
)。如果申L(fng)资源正在被另外一个线E所使用Q那么第一个线E就需要等待持有该资源?br />U程的释攑֮所需要的资源。假讄待线E持有一个那个正拥有U程所依赖的资源。下?br />的这一D代码就可以造成死锁异常现象的发生:(x)
System.Data.SqlClient.SqlException: Transaction (Process ID 12) was deadlocked
on lock resources with another process and has been chosen as the deadlock vi
ctim. Rerun the transaction.

当一个SQL Server的调用和另外一个资源发生冲H时׃(x)抛出异常Q这个资源持有一个必
要的资源。结果是Q一个进E就被终止了(jin)。当q程的IDh为系l的唯一标识的时候,q?br />?x)是一个很q_死锁的消息错误?


锁的cd
一个数据库pȝ在许多情况下都有可能锁数据项。其可能性包括:(x)

Rows—数据库表中的一整行
Pages—行的集合(通常为几kbQ?
Extents—通常是几个页的集?
Table—整个数据库?
Database—被锁的整个数据库表

除非有其它的说明Q数据库Ҏ(gu)情况自己选择最好的锁方式。不q值得感谢的是QSQL Se
rver提供?jin)一U避免默认行为的Ҏ(gu)。这是由锁提C来完成的?


提示
或许你有q许多如下的l历Q需要重设SQL Server的锁计划Qƈ且加强数据库表中锁范?br />。TansactQSQL提供?jin)一pd不同U别的锁提示Q你可以在SELECT,INSERT, UPDATE和DEL
ETE中用它们来告诉SQL Server你需要如何通过重设M的系l或事务U别来锁表格。可
以实现的提示包括Q?

FASTFIRSTROW—选取l果集中的第一行,q将其优?
HOLDLOCK—持有一个共享锁直至事务完成
NOLOCK—不允许使用׃n锁或独n锁。这可能?x)造成数据重写或者没有被认p回的?br />况;因此Q就有可能用到脏数据。这个提C只能在SELECT中用?
PAGLOCK—锁表格
READCOMMITTED—只d被事务确认的数据。这是SQL Server的默认行为?
READPAST—蟩q被其它q程锁住的行Q所以返回的数据可能?x)忽略行的内宏V这也只能在
SELECT中用?
READUNCOMMITTED—等价于NOLOCK.
REPEATABLEREAD—在查询语句中,Ҏ(gu)有数据用锁。这可以防止其它的用h新数据,
但是新的行可能被其它的用h入到数据中,q且被最新访问该数据的用戯取?
ROWLOCK—按照行的别来Ҏ(gu)据上锁。SQL Server通常锁到|者表U别来修改行Q所?br />当开发者用单行的时候,通常要重设这个设|?
SERIALIZABLE—等价于HOLDLOCK.
TABLOCK—按照表U别上锁。在q行多个有关表别数据操作的时候,你可能需要用到q?br />个提C?
UPDLOCK—当d一个表的时候,使用更新锁来代替׃n锁,q且保持一直拥有这个锁直至
事务l束。它的好处是Q可以允怽在阅L据的时候可以不需要锁Qƈ且以最快的速度
更新数据?
XLOCK—给所有的资源都上独n锁,直至事务l束?

对于数据库死锁,通常可以通过TRACE FLAG 1204?205?206Q检查ERRORLOG里面的输?br />Q和分析SQLTRACE的执行上下文判断死锁问题的来由?
TRACEON函数的第三个参数讄?1Q表CZ单单针对当前connectionQ而是针对所有包?br />未来建立的connection。这P才够完全Q否则只是监视当前已l徏立的数据库连接了(jin)?br />


执行下面的话可以把死锁记录到Errorlog中:(x)

dbcc traceon (1204, 3605, -1)
go
dbcc tracestatus(-1)
go

 

得到的输Zؓ(f)Q?
DBCC 执行完毕。如?DBCC 输出?jin)错误信息,请与pȝ理员联pR?
TraceFlag Status
--------- ------
1204      1
1205      1
3605      1

Q所影响的行Cؓ(f) 3 行)(j)

DBCC 执行完毕。如?DBCC 输出?jin)错误信息,请与pȝ理员联pR?


此后Q你可以查看数据库的例行日志Q每隔一D|_(d)数据库都?x)检查死?
2004-01-16 18:34:38.50 spid4     ----------------------------------
2004-01-16 18:34:38.50 spid4     Starting deadlock search 1976



2004-01-16 18:34:38.50 spid4     Target Resource Owner:
2004-01-16 18:34:38.50 spid4      ResType:LockOwner Stype:'OR' Mode: U SPID:55
ECID:0 Ec:(0xAA577570) Value:0x4c25cba0
2004-01-16 18:34:38.50 spid4      Node:1  ResType:LockOwner Stype:'OR' Mode: U
SPID:55 ECID:0 Ec:(0xAA577570) Value:0x4c25cba0
2004-01-16 18:34:38.50 spid4      Node:2  ResType:LockOwner Stype:'OR' Mode: U
SPID:71 ECID:0 Ec:(0xABF07570) Value:0x9bd0ba00
2004-01-16 18:34:38.50 spid4    
2004-01-16 18:34:38.50 spid4     -- next branch --
2004-01-16 18:34:38.50 spid4      Node:2  ResType:LockOwner Stype:'OR' Mode: U
SPID:71 ECID:0 Ec:(0xABF07570) Value:0x9bd0ba00
2004-01-16 18:34:38.50 spid4    
2004-01-16 18:34:38.50 spid4    
2004-01-16 18:34:38.50 spid4     End deadlock search 1976 ... a deadlock was n
ot found.
2004-01-16 18:34:38.50 spid4     ----------------------------------

DBCC TRACEON打开Q启用)(j)指定的跟t标记?

注释跟踪标记用于自定义某些控?Microsoft? SQL Server? 操作方式的特性。跟t标?br />在服务器中一直保持启用状态,直到通过执行 DBCC TRACEOFF 语句对其用为止。在发出
DBCC TRACEON 语句之前Q连入到服务器的新连接看不到M跟踪标记。一旦发语句
Q该q接p看到服务器中当前启用的所有跟t标讎ͼ即ɘq些标记是由其它q接启用Q?br />?
跟踪标记跟踪标记用于临时讄服务器的特定特征或关闭特定行为。如果启?Microsoft
? SQL Server 时设|了(jin)跟踪标记 3205Q将用带驱动E序的硬件压~。跟t标记经?br />用于诊断性能问题Q或调试存储q程或复杂的计算机系l?
下列跟踪标记?SQL Server 中可用。跟t标?描述 1204 q回参与死锁的锁的类型以?br />当前受媄(jing)响的命o(h)?
实际上可以在“错?1000 -1999”中扑ֈ他们Q?
1204 19 SQL Server 此时无法获取 LOCK 资源。请在活动用h较少旉新运行?zhn)的语?br />Q或者请求系l管理员?gu)(g)?SQL Server 锁和内存配置?
1205 13 事务Q进E?ID %1!Q与另一个进E已被死锁在资源 {%2!} 上,且该事务已被?br />作死锁牺牲品。请重新q行该事务?
1206 18 事务理器已取消?jin)分布式事务?

需要指出的是对锁的升,完全是由pȝ自行判断?而非Zؓ(f).如果要避免死锁的话,其根
本还在与数据库的设计?br />



weibogao 2007-01-12 12:56 发表评论
]]>
转《数据库设计l验?/title><link>http://www.aygfsteel.com/weibogao/archive/2007/01/11/93125.html</link><dc:creator>weibogao</dc:creator><author>weibogao</author><pubDate>Thu, 11 Jan 2007 04:09:00 GMT</pubDate><guid>http://www.aygfsteel.com/weibogao/archive/2007/01/11/93125.html</guid><wfw:comment>http://www.aygfsteel.com/weibogao/comments/93125.html</wfw:comment><comments>http://www.aygfsteel.com/weibogao/archive/2007/01/11/93125.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/weibogao/comments/commentRss/93125.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/weibogao/services/trackbacks/93125.html</trackback:ping><description><![CDATA[ <h3 class="title"> </h3> <p>2004-11-24微Y技术博?</p> <p>作者:(x) wjk.net(转蝲)</p> <p>一个成功的理pȝQ是由:(x)[50% 的业?+ 50% 的Y件] 所l成Q?50% 的成功Y件又?[25% 的数据库 + 25%的程序] 所l成Q数据库设计的好坏是一个关键。如果把企业的数据比做生?所必需的血Ԍ那么数据库的设计是应用中最重要的一部分 。有x据库设计的材料汗牛充栋,大学学位评里也有专门的讲述 。不q,如我们反复的那P再好的老师也比不过l验的教?。所以我归纳历年来所走的弯\?qing)体会(x),q在|上找了(jin)些对数据库设 计颇有造诣的专业h士给大家传授一些设计数据库的技巧和l验 。精选了(jin)其中?0 个最x巧,q把q些技巧编写成?jin)本文,Z(jin)方便索引其内容划??5 个部分:(x)</p> <p> <br /> </p> <p>W?1 部分 - 设计数据库之?</p> <p>q一部分|列?12 个基本技巧,包括命名规范和明业务需求等?</p> <p>W?2 部分 - 设计数据库表 </p> <p>d 24 个指南性技巧,늛表内字段设计以及(qing)应该避免的常见问题等?</p> <p>W?3 部分 - 选择?</p> <p>怎么选择键呢Q这里有 10 个技巧专门涉?qing)系l生成的主键的正用法,q有?时以?qing)如何?ch)引字D以获得最x能{?</p> <p>W?4 部分 - 保证数据完整?</p> <p>讨论如何保持数据库的清晰和健壮,如何把有x据降低到最程??</p> <p>W?5 部分 - 各种技?</p> <p>不包括在以上 4 个部分中的其他技巧,五花八门Q有?jin)它们希望你的数据库开发工??x)更L一些?</p> <p> <br />W?1 部分 - 设计数据库之?</p> <p> <br />考察现有环境 </p> <p>在设计一个新数据库时Q你不但应该仔细研究业务需求而且q要考察 现有的系l。大多数数据库项目都不是从头开始徏立的Q通常 Q机构内M(x)存在用来满特定需求的现有pȝQ可能没有实现自?计算Q。显?dng)现有pȝq不完美Q否则你׃必再建立新系l了(jin) 。但是对旧系l的研究可以让你发现一些可能会(x)忽略的细微问?。一般来_(d)考察现有pȝ对你l对有好处?</p> <p>定义标准的对象命名规?</p> <p>一定要定义数据库对象的命名规范。对数据库表来说 Q从目一开始就要确定表名是采用复数q是单数形式 。此外还要给表的别名定义单规则(比方_(d)如果表名是一个单?Q别名就取单词的? 个字母;如果表名是两个单词,各取两个单词的前两个字母组?4 个字母长的别名;如果表的名字?3个单词组成,你不妨从头两个单词中各取一个然后从最后一个单词中 再取Z个字母,l果q是l成 4字母长的别名Q其余依ơ类推)(j)对工作用表来_(d)表名可以加上前缀 WORK_后面附上采用该表的应用程序的名字。表内的列[字段 ]要针寚w采用一整套设计规则。比如,如果键是数字cd Q你可以?_N作ؓ(f)后缀Q如果是字符cd则可以采?_C后缀。对列[字段]名应该采用标准的前缀和后~。再?Q假如你的表里有好多"money"字段Q你不妨l每个列[字段 ]增加一?_M后缀。还有,日期列[字段]最好以 D_ 作ؓ(f)名字打头?/p> <p>(g)查表名、报表名和查询名之间的命名规范。你可能?x)很快就被这?不同的数据库要素的名U搞p涂?jin)。假如你坚持l一地命名这些数?库的不同l成部分Q至你应该在这些对象名字的开头用Table、Query 或?Report {前~加以区别?/p> <p>如果采用?Microsoft AccessQ你可以?qry、rpt、tbl ?mod {符h标识对象Q比如tbl_EmployeesQ。我在和 SQL Server 打交道的时候还用过 tbl 来烦(ch)引表Q但我用 sp_company Q现在用 sp_feft_Q标识存储过E,因ؓ(f)在有的时候如果我发现?jin)?好的处理办法往往?x)保存好几个拯。我在实?SQL Server 2000 时用udf_ Q或者类似的标记Q标识我~写的函数?</p> <p> <br />工欲善其? 必先利其?</p> <p>采用理想的数据库设计工具Q比如:(x)SyBase 公司?PowerDesignQ她支持 PB、VB、Delphe {语aQ通过 ODBC可以q接?jng)面上流行?30 多个数据库,包括 dBase、FoxPro、VFP、SQL Server {,今后有机?x)我着重介lPowerDesign 的用?</p> <p>获取数据模式资源手册 </p> <p>正在LCZ模式的h可以阅读《数据模式资源手册》一书,该书?Len Silverston、W. H. Inmon ?Kent Graziano ~写Q是一本值得拥有的最x据徏模图书。该书包括的章节늛?U数据领域,比如人员、机构和工作效能{。其他的你还可以参考:(x) [1]萨师煊王?qing)著数据库系l概?W二?高等教育出版C?1991、[2][] Steven M.Bobrowski ?Oracle 7<br />与客P服务器计技术从入门到精通刘建元{译?sh)子工业出版C,1996、[3]周中元信息系l徏模方???sh)子与信息?999q第3期,1999畅想未来Q但不可忘了(jin)q去的教训我发现询问用户如何看待未来需求变化非常有用。这样做可以辑ֈ?个目的:(x)首先Q你可以清楚C(jin)解应用设计在哪个地方应该更具灉| 性以?qing)如何避免性能瓉Q其ơ,你知道发生事先没有确定的需求变 更时用户和你一h到吃惊?/p> <p>一定要Cq去的经验教训!我们开发h员还应该通过分n自己的体 ?x)和l验互相帮助。即使用戯Z们再也不需要什么支持了(jin) Q我们也应该对他们进行这斚w的教Ԍ我们都曾l面临过q样的时 ?当初要是q么做了(jin)该多?."?</p> <p>在物理实践之前进行逻辑设计 </p> <p>在深入物理设计之前要先进行逻辑设计。随着大量?CASE工具不断涌现出来Q你的设计也可以辑ֈ相当高的逻辑水准 Q你通常可以从整体上更好C(jin)解数据库设计所需要的Ҏ(gu)面面?</p> <p>?jin)解你的业?</p> <p>在你癑ֈ癑֜定pȝ从客戯度满_需求之前不要在你的 ERQ实体关p)(j)模式中加入哪怕一个数据表Q怎么Q你q没有模?Q那请你参看技?Q。了(jin)解你的企业业务可以在以后的开发阶D节U大量的旉 。一旦你明确?jin)业务需求,你就可以自己做出许多决策?jin)?/p> <p>一旦你认ؓ(f)你已l明了(jin)业务内容Q你最好同客户q行一ơ系l的?。采用客L(fng)术语q且向他们解释你所惛_的和你所听到?。同时还应该用可能、将?x)和必须{词汇表辑ևpȝ的关pd?。这样你可以让你的客户U正你自q理解然后做好下一步的ER 设计?</p> <p>创徏数据字典?ER 图表 </p> <p>一定要q旉创徏 ER 图表和数据字典。其中至应该包含每个字D늚数据cd和在每个?内的d键。创?ER<br />图表和数据字典确实有点费时但对其他开发h员要?jin)解整个设计却?完全必要的。越早创能有助于避免今后面(f)的可能؜?Q从而可以让M?jin)解数据库的人都明确如何从数据库中获得数据?/p> <p>有一份诸?ER 图表{最新文档其重要性如何强调都不过分,q对表明表之间关pd 有用Q而数据字典则说明?jin)每个字D늚用途以?qing)Q何可能存在的别名 。对SQL 表达式的文档化来说这是完全必要的?</p> <p>创徏模式 </p> <p>一张图表胜q千a万语Q开发h员不仅要阅读和实现它 Q而且q要用它来帮助自己和用户对话。模式有助于提高协作效能 Q这样在先期的数据库设计中几乎不可能出现大的问题 。模式不必弄的很复杂Q甚臛_以简单到手写在一张纸上就可以?。只是要保证其上的逻辑关系今后能生效益?</p> <p>从输入输Z?</p> <p>在定义数据库表和字段需求(输入Q时Q首先应(g)查现有的或者已l?设计出的报表、查询和视图Q输出)(j)以决定ؓ(f)?jin)支持这些输出哪些?必要的表和字Dc(din)D个简单的例子Q假如客户需要一个报表按照邮?~码排序、分D和求和Q你要保证其中包括了(jin)单独的邮政编码字D?不要把邮政编码糅q地址字段里?</p> <p>报表技?</p> <p>要了(jin)解用户通常是如何报告数据的Q批处理q是在线提交报表 Q时间间隔是每天、每周、每月、每个季度还是每q?Q如果需要的话还可以考虑创徏ȝ表。系l生成的主键在报表中?隄理。用户在hpȝ生成主键的表内用副键q行(g)索往往?x)返?许多重复数据。这L(fng)(g)索性能比较低而且Ҏ(gu)引v混ؕ?</p> <p>理解客户需?</p> <p>看v来这应该是显而易见的事,但需求就是来自客?Q这里要从内部和外部客户的角度考虑Q。不要依赖用户写下来的需 求,真正的需求在客户的脑袋里。你要让客户解释光?Q而且随着开发的l箋Q还要经常询问客户保证其需求仍然在开发的 目的之中。一个不变的真理是:(x)"只有我看见了(jin)我才知道我想要的?什?必然?x)导致大量的q工Q因为数据库没有辑ֈ客户从来没有?下来的需求标准。而更p的是你对他们需求的解释只属于你自己 Q而且可能是完全错误的?</p> <p> <br />W?2 部分 - 设计表和字段 </p> <p> <br />(g)查各U变?</p> <p>我在设计数据库的时候会(x)考虑到哪些数据字D将来可能会(x)发生变更 。比方说Q姓氏就是如此(注意是西方h的姓氏,比如x结婚后?夫姓{)(j)。所以,在徏立系l存储客户信息时Q我們֐于在单独的一 个数据表里存储姓氏字D,而且q附加v始日和终止日{字D?Q这样就可以跟踪q一数据条目的变化?</p> <p>采用有意义的字段?</p> <p>有一回我参加开发过一个项目,其中有从其他E序员那里承的E序 Q那个程序员喜欢用屏q上昄数据指示用语命名字段Q这也不?Q但不幸的是Q她q喜Ƣ用一些奇怪的命名法,其命名采用了(jin)匈牙?命名和控制序L(fng)l合形式Q比如cbo1、txt2、txt2_b {等?br />除非你在使用只面向你的羃写字D名的系l,否则请尽可能地把字段 描述的清楚些。当?dng)也别做过头?jin)Q比如Customer_Shipping_Address _Street_Line_1Q虽然很富有说明?Q但没h愿意键入q么长的名字Q具体尺度就在你的把握中?br />采用前缀命名。如果多个表里有好多同一cd的字D(比如 FirstNameQ,你不妨用特定表的前缀Q比?CusLastNameQ来帮助你标识字Dc(din)?/p> <p>时效性数据应包括"最q更新日?旉"字段。时间标记对查找?据问题的原因、按日期重新处理/重蝲数据和清除旧数据特别有用?br />标准化和数据驱动数据的标准化不仅方便?jin)自p且也方便了(jin)其他人。比方说 Q假如你的用L(fng)面要讉K外部数据源(文g、XML<br />文档、其他数据库{)(j)Q你不妨把相应的q接和\径信息存储在用户 界面支持表里。还有,如果用户界面执行工作之cȝd Q发送邮件、打CW、修改记录状态等Q,那么产生工作的数据 也可以存攑֜数据库里。预先安排总需要付出努力,但如果这些过E?采用数据驱动而非编码的方式Q那么策略变更和l护都会(x)方便得多 。事实上Q如果过E是数据驱动的,你就可以把相当大的责Ll用 Pqhl护自己的工作流q程?</p> <p>标准化不能过?</p> <p>寚w些不熟?zhn)标准化一词(normalizationQ的言 Q标准化可以保证表内的字D都是最基础的要素,而这一措施有助?消除数据库中的数据冗余。标准化有好几种形式Q但Third Normal FormQ?NFQ通常被认为在性能、扩展性和数据完整性方面达 C(jin)最好^衡。简单来_(d)3NF 规定Q?br />* 表内的每一个值都只能被表达一ơ?br />* 表内的每一行都应该被唯一的标识(有唯一键)(j)?br />* 表内不应该存储依赖于其他键的非键信息?br />遵守 3NF 标准的数据库h以下特点Q有一l表专门存放通过键连接v来的?联数据。比方说Q某个存攑֮户及(qing)其有兛_单的 3NF<br />数据库就可能有两个表QCustomer ?Order。Order 表不包含定单兌客户的Q何信息,但表内会(x)存放一个键?Q该键指向Customer 表里包含该客户信息的那一行?br />更高层次的标准化也有Q但更标准是否就一定更好呢Q答案是不一?。事实上Q对某些目来说Q甚臛_q?3NF 都可能给数据库引入太高的复杂性?/p> <p>Z(jin)效率的缘故,对表不进行标准化有时也是必要?Q这L(fng)例子很多。曾l有个开发餐饮分析Y件的zd是用非标准化 表把查询旉从^?40U降低到?jin)两U左叟뀂虽然我不得不这么做Q但我绝不把数据表的?标准化当作当然的设计理念。而具体的操作不过是一U派?。所以如果表Z(jin)问题重新产生非标准化的表是完全可能的?</p> <p>Microsoft Visual FoxPro 报表技?</p> <p>如果你正在?Microsoft Visual FoxProQ你可以用对用户友好的字D名来代替编L(fng)名称 Q比如用 Customer Name 代替 txtCNaM。这P当你用向导程?[WizardsQ台湾hUCؓ(f)'_'] 创徏表单和报表时Q其名字?x)让那些不是E序员的人更Ҏ(gu)阅读?</p> <p>不活跃或者不采用的指C符 </p> <p>增加一个字D表C所在记录是否在业务中不再活跃挺有用?。不是客户、员工还是其他什么hQ这样做都能有助于再q行查询 的时候过滤活跃或者不z跃状态。同时还消除?jin)新用户在采用数据?所面(f)的一些问题,比如Q某些记录可能不再ؓ(f)他们所?Q再删除的时候可以vC定的防范作用?</p> <p>使用角色实体定义属于某类别的列[字段] </p> <p>在需要对属于特定cd或者具有特定角色的事物做定义时 Q可以用角色实体来创建特定的旉兌关系Q从而可以实现自我文 档化?br />q里的含义不是让 PERSON 实体带有 Title 字段Q而是_(d)Z么不?PERSON 实体?PERSON_TYPE实体来描qCh员呢Q比方说Q当 John Smith, Engineer 提升?John Smith, Director 乃至最后爬到John Smith, CIO 的高位,而所有你要做的不q是改变两个?PERSON ?PERSON_TYPE之间关系的键|同时增加一个日?旉字段来知道变化是何时?生的。这P你的 PERSON_TYPE 表就包含?jin)所?PERSON的可能类型,比如 Associate、Engineer、Director 、CIO 或?CEO {?br />q有个替代办法就是改?PERSON 记录来反映新头衔的变化,不过q样一来在旉上无法跟t个人所?位置的具体时间?</p> <p>采用常用实体命名机构数据 </p> <p>l织数据的最单办法就是采用常用名字,比如QPERSON 、ORGANIZATION、ADDRESS ?PHONE{等。当你把q些常用的一般名字组合v来或者创建特定的相应副实 体时Q你得C(jin)自己用的Ҏ(gu)版本。开始的时候采用一般术语的?要原因在于所有的具体用户都能Ҏ(gu)象事物具体化?br />有了(jin)q些抽象表示Q你可以在W?2 U标识中采用自己的特D名Uͼ比如QPERSON 可能是Employee、Spouse、Patient、Client 、Customer、Vendor 或?Teacher{。同L(fng)QORGANIZATION 也可能是<br />MyCompany、MyDepartment、Competi tor、Hospital、Warehouse、Governm ent {。最后ADDRESS 可以具体?Site、Location、Home、Work、Client 、Vendor、Corporate 和FieldOffice {?br />采用一般抽象术语来标识"事物"的类别可以让你在兌数据以满?业务要求斚w获得巨大的灵zL,同时q样做还可以显著降低数据?储所需的冗余量?</p> <p>用户来自世界各地 </p> <p>在设计用到网l或者具有其他国际特性的数据库时Q一定要C大多 数国安有不同的字段格式Q比如邮政编码等Q有些国?Q比如新西兰没有邮政编码一说?</p> <p>数据重复需要采用分立的数据?</p> <p>如果你发现自己在重复输入数据Q请创徏新表和新的关pR?br />每个表中都应该添加的 3 个有用的字段<br />* dRecordCreationDateQ在 VB 下默认是 Now()Q而在 SQL Server 下默认ؓ(f) GETDATE()<br />* sRecordCreatorQ在 SQL Server 下默认ؓ(f) NOT NULL DEFAULT USER<br />* nRecordVersionQ记录的版本标记Q有助于准确说明 记录中出?null 数据或者丢失数据的原因<br />对地址和电(sh)话采用多个字D?br />描述街道地址q短一行记录是不够的。Address _Line1、Address_Line2 ?Address_Line3<br />可以提供更大的灵zL。还有,?sh)话L(fng)和邮件地址最好拥有自q 数据表,光h自n的类型和标记cd?/p> <p>q分标准化可要小?j),q样做可能会(x)D性能上出现问?。虽然地址和电(sh)话表分离通常可以辑ֈ最佳状态,但是如果需要经?讉Kq类信息Q或许在其父表中存放"首?信息Q比?br />Customer {)(j)更ؓ(f)妥当些。非标准化和加速访问之间的妥协是有一定意义的?</p> <p>使用多个名称字段 </p> <p>我觉得很吃惊Q许多h在数据库里就l?name留一个字Dc(din)我觉得只有刚入门的开发h员才?x)这么?Q但实际上网上这U做法非常普遍。我应该把姓氏和名字当作?个字D|处理Q然后在查询的时候再把他们组合v来?/p> <p>我最常用的是在同一表中创徏一个计列[字段]Q通过它可以自?地连接标准化后的字段Q这h据变动的时候它也跟着变。不q?Q这样做在采用徏模Y件时得很机灵才行。MQ采用连接字D늚?式可以有效的隔离用户应用和开发h员界面?br />提防大小写؜用的对象名和Ҏ(gu)字符q去最令我恼火的事情之一是数据库里有大写L(fng)的对象名 Q比?CustomerData。这一问题?Access ?Oracle数据库都存在。我不喜Ƣ采用这U大写L(fng)的对象命名方?Q结果还不得不手工修改名字。想想看Q这U数据库 /应用E序能؜到采用更强大数据库的那一天吗Q采用全部大写而且 包含下划W的名字h更好的可L(CUSTOMER_DATA Q,l对不要在对象名的字W之间留I格?</p> <p>心(j)保留?</p> <p>要保证你的字D名没有和保留词、数据库pȝ或者常用访问方法冲H?Q比如,最q我~写的一?ODBC q接E序里有个表Q其中就用了(jin) DESC作ؓ(f)说明字段名。后果可惌知QDESC ?DESCENDING ~写后的保留词。表里的一?SELECT *语句倒是能用Q但我得到的却是一大堆毫无用处的信息?</p> <p>保持字段名和cd的一致?</p> <p>在命名字Dƈ为其指定数据cd的时候一定要保证一致?。假如字D在某个表中叫做"agreement_number" Q你别在另一个表里把名字Ҏ(gu)"ref1"。假如数据类型在一 个表里是整数Q那在另一个表里可别变成字符型了(jin)。记?Q你q完自己的活?jin),其他要用你的数据库呢?</p> <p>仔细选择数字cd </p> <p>?SQL 中?smallint ?tinyint cd要特别小?j),比如Q假如你想看看月销售总额Q你的总额字段c?型是smallintQ那么,如果总额过?$32,767 你就不能q行计算操作?jin)?</p> <p>删除标记 </p> <p>在表中包含一?删除标记"字段Q这样就可以把行标记为删?。在关系数据库里不要单独删除某一行;最好采用清除数据程序而且 要仔l维护烦(ch)引整体性?</p> <p>避免使用触发?</p> <p>触发器的功能通常可以用其他方式实现。在调试E序时触发器可能?为干扰。假如你实需要采用触发器Q你最好集中对它文档化?br />包含版本机制你在数据库中引入版本控制机制来确定用中的数据库的版?。无论如何你都要实现q一要求。时间一长,用户的需求L?x)改?的。最l可能会(x)要求修改数据库结构。虽然你可以通过(g)查新字段?者烦(ch)引来定数据库结构的版本Q但我发现把版本信息直接存放到数 据库中不更ؓ(f)方便吗? </p> <p>l文本字D늕余?</p> <p>ID cd的文本字D,比如客户 ID或定单号{等都应该设|得比一般想象更大,因ؓ(f)旉不长你多半就 ?x)因d额外的字W而难堪不巌Ӏ比方说Q假设你的客?ID ?10位数ѝ那你应该把数据库表字段的长度设?12 或?13 个字W长。这浪费空间吗Q是有一点,但也没你惌的那么多 Q一个字D加?3个字W在?1 百万条记录,再加上一点烦(ch)引的情况下才不过让整个数据库多占?3MB的空间。但q额外占据的I间却无需来重构整个数据库就可以实现 数据库规模的增长?jin)。n份证的号码从 15 位变?18<br />位就是最好和最惨痛的例子?</p> <p>列[字段]命名技?</p> <p>我们发现Q假如你l每个表的列[字段]名都采用l一的前~ Q那么在~写 SQL表达式的时候会(x)得到大大的简化。这样做也确实有~点 Q比如破坏了(jin)自动表连接工L(fng)作用Q后者把公共列[字段 ]名同某些数据库联pv来,不过pq些工具有时不也q接错误?。D个简单的例子Q假设有两个表:(x)<br />Customer ?Order。Customer 表的前缀是cu_Q所以该表内的子D名如下Qcu_name_id、cu _surname、cu_initials 和cu_address {。Order表的前缀?or_Q所以子D名是:(x)<br />or_order_id、or_cust_name_id、or _quantity ?or_denoscription {?br />q样从数据库中选出全部数据?SQL 语句可以写成如下所C:(x)<br />Select * From Customer, Order Where cu_surname = "MYNAME" ;<br />and cu_name_id = or_cust_name_id and or_quantity = 1<br />在没有这些前~的情况下则写成这个样子(用别名来区分Q:(x)<br />Select * From Customer, Order Where Customer.surname = "MYNAME" ;<br />and Customer.name_id = Order.cust_name_id and Order.quantity = 1<br />W?1 ?SQL 语句没少键入多少字符。但如果查询涉及(qing)?5 个表乃至更多的列[字段]你就知道q个技巧多有用?jin)?</p> <p>W?3 部分 - 选择键和索引 </p> <p> <br />数据采掘要预先计?</p> <p>我所在的某一客户部门一度要处理 8万多份联pL式,同时填写每个客户的必要数据(q绝对不是小z)(j) 。我从中q要定Zl客户作为市(jng)场目标。当我从最开始设计表?字段的时候,我试图不在主索引里增加太多的字段以便加快数据库的 q行速度。然后我意识到特定的l查询和信息采掘既不准确速度也不 快。结果只好在ȝ(ch)引中重徏而且合ƈ?jin)数据字Dc(din)我发现有一个指 C划相当关键——当我想创徏pȝcd查找时ؓ(f)什么要采用L(fng)?Z索引字段呢?我可以用传真L(fng)q行(g)索,但是它几乎就象系l?cd一样对我来说ƈ不重要。采用后者作Z字段Q数据库更新后重 新烦(ch)引和(g)索就快多?jin)?/p> <p>可操作数据仓库(ODSQ和数据仓库QDWQ这两种环境下的数据 索引是有差别的。在 DW环境下,你要考虑销售部门是如何l织销售活动的。他们ƈ不是数据 库管理员Q但是他们确定表内的键信息。这里设计h员或者数据库?作h员应该分析数据库l构从而确定出性能和正输Z间的最x 件?</p> <p>使用pȝ生成的主?</p> <p>q类同技?1Q但我觉得有必要在这里重复提醒大家。假如你L在设计数据库 的时候采用系l生成的键作Z键,那么你实际控制了(jin)数据库的索引 完整性。这P数据库和非h工机制就有效地控制了(jin)对存储数据中?一行的讉K?br />采用pȝ生成键作Z键还有一个优点:(x)当你拥有一致的键结构时 Q找到逻辑~陷很容易?</p> <p>分解字段用于索引 </p> <p>Z(jin)分离命名字段和包含字D以支持用户定义的报?Q请考虑分解其他字段Q甚至主键)(j)为其l成要素以便用户可以对其 q行索引。烦(ch)引将加快 SQL和报表生成器脚本的执行速度。比方说Q我通常在必M?SQL LIKE 表达式的情况下创建报表,因ؓ(f) case number 字段无法分解为year、serial number、case type ?defendant code{要素。性能也会(x)变坏。假如年度和cd字段可以分解为烦(ch)引字D那 么这些报表运行v来就?x)快多?jin)?</p> <p>键设?4 原则 </p> <p>* 为关联字D创建外键?br />* 所有的键都必须唯一?br />* 避免使用复合键?br />* 外键L兌唯一的键字段?</p> <p>别忘?jin)?ch)?</p> <p>索引是从数据库中获取数据的最高效方式之一?5%的数据库性能问题都可以采用烦(ch)引技术得到解冟뀂作Z条规?Q我通常寚w辑主键使用唯一的成l烦(ch)引,对系l键Q作为存储过E?Q采用唯一的非成组索引Q对M外键列[字段]采用非成l烦(ch)?。不q,索引p是盐Q太多了(jin)菜就怺(jin)。你得考虑数据库的I间?多大Q表如何q行讉KQ还有这些访问是否主要用作读写?/p> <p>大多数数据库都烦(ch)引自动创建的主键字段Q但是可别忘?jin)?ch)引外?Q它们也是经怋用的键,比如q行查询昄主表和所有关联表的某 条记录就用得上。还有,不要索引memo/note 字段Q不要烦(ch)引大型字D(有很多字W)(j)Q这样作?x)让索引占用太?的存储空间?br />不要索引常用的小型表不要为小型数据表讄M键,假如它们l常有插入和删除操作更 别这样作?jin)。对q些插入和删除操作的索引l护可能比扫描表I间?耗更多的旉?br />不要把社?x)保障号码(SSNQ或w䆾证号码(IDQ选作键?br />永远都不要?SSN ?ID 作ؓ(f)数据库的键。除?jin)隐U原因以外,ȝ政府来趋向于不准??SSN ?ID<br />用作除收入相关以外的其他目的QSSN ?ID需要手工输入。永q不要用手工输入的键作Z?Q因Z旦你输入错误Q你唯一能做的就是删除整个记录然后从头开 始?/p> <p>我在破解他h的程序时候,我看到很多h?SSN ?IDq曾被用做系列号Q当然尽这么做是非法的。而且Z也都知道q?是非法的Q但他们已经?fn)惯了(jin)。后来,随着盗取w䆾犯罪案g的增?Q我现在的同行正痛苦C一大摊子数据中?SSN ?ID 删除?</p> <p>不要用用L(fng)?</p> <p>在确定采用什么字D作的键的时候,可一定要心(j)用户要~辑 的字Dc(din)通常的情况下不要选择用户可编辑的字段作ؓ(f)?。这样做?x)迫使你采取以下两个措施Q?br />* 在创录之后对用户~辑字段的行为施加限制。假如你q么做了(jin) Q你可能?x)发C的应用程序在商务需求突然发生变?Q而用户需要编辑那些不可编辑的字段时缺乏够的灉|?。当用户在输入数据之后直C存记录才发现pȝZ(jin)问题他们该?么想Q删除重建?假如记录不可重徏是否让用戯开Q?br />* 提出一些检和U正键冲H的Ҏ(gu)。通常Q费点精力也搞定了(jin) Q但是从性能上来看这样做的代价就比较大了(jin)。还?Q键的纠正可能会(x)q你突破你的数据和商业/用户界面层之间的?R?br />所以还是重提一句老话Q你的设计要适应用户而不是让用户来适应?的设计?/p> <p>不让主键h可更新性的原因是在关系模式下,主键实现?jin)不同表?间的兌。比如,Customer 表有一个主键CustomerIDQ而客L(fng)定单则存攑֜另一个表?。Order 表的主键可能?OrderNo 或?OrderNo、CustomerID和日期的l合。不你选择哪种键设|,你都需要在 Order 表中存放 CustomerID 来保证你可以l下定单的用h到其定单记录?br />假如你在 Customer 表里修改?CustomerIDQ那么你必须扑և Order表中的所有相兌录对其进行修攏V否则,有些定单׃(x)不属于Q?客户——数据库的完整性就完蛋了(jin)?br />如果索引完整性规则施加到表一U,那么在不~写大量代码和附加删 除记录的情况下几乎不可能改变某一条记录的键和数据库内所有关?的记录。而这一q程往往错误丛生所以应该尽量避免?</p> <p>可选键(候选键)有时可做主键 </p> <p>CQ查询数据的不是机器而是人?br />假如你有可选键Q你可能q一步把它用做主键。那L(fng)?Q你拥有了(jin)建立强大索引的能力。这样可以阻止用数据库的h?得不q接数据库从而恰当的qo(h)数据。在严格控制域表的数据库?Q这U负载是比较醒目的。如果可选键真正有用Q那是辑ֈ?jin)主?的水准?br />我的看法是,假如你有可选键Q比如国家表内的state_codeQ你不要在现有不能变动的唯一键上创徏后箋 的键。你要做的无非是创徏毫无价值的数据。如你因度用表?后箋键[别名]建立q种表的兌Q操作负载真得需要考虑一下了(jin)?</p> <p>别忘?jin)外?</p> <p>大多数数据库索引自动创徏的主键字Dc(din)但别忘?jin)?ch)引外键字D?Q它们在你想查询主表中的记录?qing)其兌记录时每ơ都会(x)用到。还?Q不要烦(ch)引memo/notes 字段而且不要索引大型文本字段Q许多字W)(j)Q这样做?x)让你的索?占据大量的数据库I间?</p> <p>W?4 部分 - 保证数据的完整?</p> <p>用约束而非商务规则强制数据完整?</p> <p>如果你按照商务规则来处理需求,那么你应当检查商务层?/用户界面Q如果商务规则以后发生变化,那么只需要进行更新即?。假如需求源于维护数据完整性的需要,那么在数据库层面上需要施 加限制条件。如果你在数据层实采用?jin)约束,你要保证有办法把?C能通过U束(g)查的原因采用用户理解的语a通知用户界面 。除非你的字D命名很冗长Q否则字D名本nq不够?/p> <p>只要有可能,请采用数据库pȝ实现数据的完整性。这不但包括通过 标准化实现的完整性而且q包括数据的功能性。在写数据的时候还?以增加触发器来保证数据的正确性。不要依赖于商务层保证数据完?性;它不能保证表之间Q外键)(j)的完整性所以不能强加于其他完整?规则之上?</p> <p>分布式数据系l?</p> <p>对分布式pȝ而言Q在你决定是否在各个站点复制所有数据还是把?据保存在一个地方之前应该估计一下未?5 q或?10<br />q的数据量。当你把数据传送到其他站点的时候,最好在数据库字D?中设|一些标记。在目的站点收到你的数据之后更新你的标记 。ؓ(f)?jin)进行这U数据传输,请写下你自己的批处理或者调度程序以?定时间间隔运行而不要让用户在每天的工作后传输数?。本地拷贝你的维护数据,比如计算常数和利息率{?Q设|版本号保证数据在每个站炚w完全一致?</p> <p>强制指示完整?参照完整?) </p> <p>没有好办法能在有x据进入数据库之后消除它,所以你应该在它q?入数据库之前其剔除。激zL据库pȝ的指C完整性特?。这样可以保持数据的清洁而能q开发h员投入更多的旉处理错误条g?</p> <p>关系 </p> <p>如果两个实体之间存在多对一关系Q而且q有可能转化为多对多关系 Q那么你最好一开始就讄成多对多关系。从现有的多对一关系转变 为多对多关系比一开始就是多对多关系要难得多?</p> <p>采用视图 </p> <p>Z(jin)在你的数据库和你的应用程序代码之间提供另一层抽?Q你可以Z的应用程序徏立专门的视图而不必非要应用程序直接访 问数据表。这样做q等于在处理数据库变更时l你提供?jin)更多的自??</p> <p>l数据保有和恢复制定计划 </p> <p>考虑数据保有{略q包含在设计q程中,预先设计你的数据恢复q程 。采用可以发布给用户/开发h员的数据字典实现方便的数据识别同 时保证对数据源文档化。编写在U更新来"更新查询 "供以后万一数据丢失可以重新处理更新?br />用存储过E让pȝ做重z解决了(jin)许多ȝ(ch)来生一个具有高度完整性的数据库解x案之?Q我军_装一些关联表的功能组Q提供一整套常规的存储过E来?问各l以便加快速度和简化客L(fng)序代码的开发。数据库不只是一?存放数据的地方,它也是简化编码之地?</p> <p>使用查找 </p> <p>控制数据完整性的最x式就是限制用L(fng)选择。只要有可能都应?提供l用户一个清晰的价值列表供光择。这样将减少键入代码的错 误和误解同时提供数据的一致性。某些公共数据特别适合查找 Q国家代码、状态代码等?</p> <p> <br />W?5 部分 - 各种技?</p> <p>文档、文档、文?</p> <p>Ҏ(gu)有的快捷方式、命名规范、限制和函数都要~制文档?/p> <p>采用l表、列[字段]、触发器{加注释的数据库工具。是?Q这有点费事Q但从长q来看,q样做对开发、支持和跟踪修改非常 有用?/p> <p>取决于你使用的数据库pȝQ可能有一些Y件会(x)l你一些供你很快上 手的文档。你可能希望先开始在_(d)然后获得来多的细?。或者你可能希望周期性的预排Q在输入新数据同旉着你的q展?每一部分l节化。不你选择哪种方式Q总要对你的数据库文档?Q或者在数据库自w的内部或者单独徏立文档。这?Q当你过?jin)一q多旉后再回过头来做第2 个版本,你犯错的Z(x)大大减?</p> <p>使用常用pQ或者其他Q何语aQ而不要用编?</p> <p>Z么我们经帔R用编码(比如 9935A 可能?青岛啤酒'的供应代码,4XF788-Q可能是帐目编码)(j)Q理由很多。但是用户通常都用pq行思考而不 是编码。工?5 q的?x)计或许知?4XF788-Q是什么东西,但新来的可就不一定了(jin)。在创徏下拉菜单、列?、报表时最好按照英语名排序。假如你需要编码,那你可以在编码旁 附上用户知道的英语?</p> <p>保存常用信息 </p> <p>让一个表专门存放一般数据库信息非常有用。我常在q个表里存放?据库当前版本、最q检?修复Q对FoxProQ、关联设计文档的名称、客L(fng)信息 。这样可以实CU简单机制跟t数据库Q当客户抱怨他们的数据?没有辑ֈ希望的要求而与你联pLQ这样做寚w客户?/服务器环境特别有用?</p> <p>试、测试、反复测?</p> <p>建立或者修订数据库之后Q必ȝ用户新输入的数据试数据字段 。最重要的是Q让用户q行试q且同用户一道保证你选择的数据类 型满_业要求。测试需要在把新数据库投入实际服务之前完成?</p> <p>(g)查设?</p> <p>在开发期间检查数据库设计的常用技术是通过其所支持的应用程序原 型检查数据库。换句话_(d)针对每一U最l表达数据的原型应用 Q保证你(g)查了(jin)数据模型q且查看如何取出数据?</p> <p>Microsoft Visual FoxPro 设计技?</p> <p>对复杂的 Microsoft Visual FoxPro数据库应用程序而言Q可以把所有的主表攑֜一个数据库容器文g?Q然后增加其他数据库表文件和装蝲同原有数据库有关的特D文?。根据需要用q些文gq接C文g中的主表。比如数据输?、数据烦(ch)引、统计分析、向理层或者政府部门提供报表以?qing)各cd L询等。这一措施化了(jin)用户和组权限的分配,而且有利于应用程 序函敎ͼ存储q程Q的分组和划分,从而在E序必须修改的时候易?理?</p> <img src ="http://www.aygfsteel.com/weibogao/aggbug/93125.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/weibogao/" target="_blank">weibogao</a> 2007-01-11 12:09 <a href="http://www.aygfsteel.com/weibogao/archive/2007/01/11/93125.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转《“数据徏模”读书笔??/title><link>http://www.aygfsteel.com/weibogao/archive/2007/01/11/93122.html</link><dc:creator>weibogao</dc:creator><author>weibogao</author><pubDate>Thu, 11 Jan 2007 04:01:00 GMT</pubDate><guid>http://www.aygfsteel.com/weibogao/archive/2007/01/11/93122.html</guid><wfw:comment>http://www.aygfsteel.com/weibogao/comments/93122.html</wfw:comment><comments>http://www.aygfsteel.com/weibogao/archive/2007/01/11/93122.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/weibogao/comments/commentRss/93122.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/weibogao/services/trackbacks/93122.html</trackback:ping><description><![CDATA[ <h3 class="title"> </h3> <p>         最q逛书店发C本数据徏模的好书——《数据徏模:(x)分析与设计的工具和技巧?Data Modeler's WorkbenchQTools and Techniques for Analysis and Design)Q作者Steve Hoberman。粗d一遍后Q感觉这本书的确无愧于译者和国外专家们的盛赞Q“这本书充满?jin)对改进数据模型和设计有益的技术和技巧,q且它还极富阅读乐趣——一个了(jin)不v的结合!M一个数据徏模者都应该拥有一本Steve Hoberman的关于数据徏模工具和技术的书。?/p> <p>  管我对自己所掌握的数据徏模知识有一定的自负Q读完该书后Q还是获益良多。本着好书大家一起分享的xQ我把该书的每个章节的ȝ和技巧徏议列出来Q以方便手头暂时没有该书的朋友在数据建模时参考。该书所介绍的工具和模版可在作者的Web站点下蝲Q地址是:(x)<br />  www.wiley.com/compbooks/hoberman</p> <p>  W一章:(x)使用闻、类比和演示文稿来阐明数据徏模的概念</p> <p>  在一般的日常沟通中。我们可能会(x)说出q听到许多故事、或者趣闻这些故事涉?qing)的论题范围很大。有些例子是周末发生在我们自pn边的事情Q或者是与我们的工作目有关的经历。这些趣L助于加强我们和周围h们的关系Q增q我们的愉?zhn)情AQ而且Ҏ(gu)们有教育作用。我们能够把pa表达出来的东西Ş象化。有Ӟ当故事结束时Q给我们留下的是以前未曾惛_的信息或更多的认识。在解释数据建模概念Ӟ闻是极其有效的。原因有如下几个Q?br />  它们建立h久的形象?br />  它们引h入胜、人愉(zhn)?br />  它们增经Z之间的关pR?br />  它们减缓压力?/p> <p>  成功~造ƈ讲述一个数据徏模方面的闻有下面三个简单的步骤Q?br />  1)定义一个论题。要在心(j)中保证,你讲q的q个闻有一个特定的目标或论题,也就是说Q这个故事是Z(jin)解释一个数据徏模的概念或术语?br />  2)选择你的故事。我们可以选择的故事类型多U多栗我们要考虑选择一个有ƈ有益Q而且能够明白无误C达主题意囄短的故事?br />  3)演练你的故事。一旦找C(jin)合适的故事Q你要好好演l一番,直到你自信它能够在两分钟的时间内充分表达你的论题。要避免讲述拖拖拉拉的故事?/p> <p>  数据模型cL<br />  cL是把两个或多个概念q行怺比较Q以它们之间的相似或差异。类比是介绍外来事物或新鲜事物的一个很好的技巧,其是向非计机专业的h士介l计机的专业知识时。Hoberman在数据徏模中最常见的几个类比如下(他用q些cLL的打动管理层l他涨了(jin)一倍的工资^_^Q:(x)<br />  M域模型是一个居高(f)下的视点?br />  数据模型是一个设计图?br />  企业模型是一个世界地图?br />  标准是城市(jng)规划?br />  元数据仓储库是一个图书馆?br />  数据仓库是“心(j)脏”?/p> <p>  W二章:(x)元数据宾果游?br />  单来_(d)即通过宾果卡片游戏的方式,调动目团队成员的积极性,来确定数据模型,q确定元数据的有效性。元数据宾果游戏“共赢”,如果q气好,游戏l束时每个h都能赢?/p> <p>  W三章:(x)保高质量的定义<br />  本章集中讨论一个被UCؓ(f)“定义检查单?Definition Checklist)的工P它包含了(jin)保定义的质量处于最高水q的准则?/p> <p>  W四章:(x)数据建模者的目计划<br />  本章重点介绍定数据建模阶段、Q务、工具和旉的四个工P(x)<br />  ·数据建模阶段的工P(x)用来定最高层ơ上的数据徏模步骤?br />  ·阶段—Q务—工P(x)提取出“数据徏模阶D”的各个阶段q把他们分解成数据徏模Q务?br />  ·优先U三角ŞQ你可以从以下三中取两Ҏ(gu)|(x)很高的质量、最短的旉与最低的成本Q但你永q也别想三者兼得?br />  ·可靠的估工P(x)“主体域工作量时限”根据应用程序的cdQ确定每个数据徏模阶D应占整个项目的癑ֈ比。“Q务工作量工具”提取在“阶D—Q务—工具”中定的每Q务,q列出它们应占整个数据徏模工作品的癑ֈ比。这两个工具的组合可使你向项目经理提供一份具有一定精度的合理估?/p> <p>  W五章:(x)M域分?br />  本章主要探讨五个关键的工Pq五个工具对数据建模工作的主体域分析阶段有帮l作用。它们应该按照下面的序被逐个完成Q?br />  1)M域检查单Q新应用E序中的M域的完整列表Q还有各个主体域的定义和同义词(或别名)(j)?br />  2)M域CRUD(Create Read Update Delete)矩阵Q包含新应用E序和现有应用程序之间的M域方面的差别和重复之处,定应用E序的范围?br />  3)In-the-Know模版Q确定完成这个新应用E序的数据间模工作品所需要的、被用作资源的h员和文档?br />  4)M域家族树(wi)Q包含每一个主体域的源应用E序和若q其他的关键信息Q阐明主体域数据来自哪里?br />  5)M域力度矩阵:(x)使用一个电(sh)子表格的格式Q记录每一个度量和事实M域的发布层次?/p> <p>  W六章:(x)M域徏?br />  本章阐述三个队主体域信息q行建模的强大工P(x)<br />  ·“业务清理板”模型?br />  ·“应用程序清理板”模型?br />  ·“早期现实性检查”模型?/p> <p>  W七章:(x)逻辑数据分析<br />  本章x四个逻辑数据分析工具Q它们应该按照下面的ơ序被用:(x)<br />  1)数据元素家族?wi)?x)包含应用E序的数据元素的完整列表Q以?qing)每个数据元素的来源和变换信息,q有其他几个关键的数据元素元数据?br />  2)数据元素_度矩阵Q用一个电(sh)子表格的格式Q来记录每个度量和事实的发布层次?br />  3)数据质量记录模板Q展C每个数据元素的员数据和一些实际数据的Ҏ(gu)?br />  4)数据质量认模板Q记录每个数据元素的元数据和一些实际数据的Ҏ(gu)的结果?/p> <p>  W八章:(x)规范化之旅和反向规范化生存指南(强烈推荐Q是我目前所读过最好的关系型数据库的规范化技术文档)(j)<br />  规范化是一个剔除冗余ƈ应用规则的过E,它的目的是ؓ(f)?jin)更好的理解和表辑֭在于数据元素之间的依赖性和参与性。规范化包含6个层ơ,最高层是第五范?5NF)。一般的技术文档上都认?NF卛_QSteve Hobermanl我们指明了(jin)更高的目标:(x)5NF。Graeme Simsion写过一本名为《Data Modeling Essentials》的书,在这本书中,他写道:(x)“较高层ơ的范式常被从业者误解ƈ因此而被忽视Q或Z(jin)支持不可靠的建模旉而被引用。”但是,我们需要理解这些较高层ơ的规范化,因ؓ(f)它们体现?jin)额外的规范化机会(x),q帮l我们进一步减冗余信息、改q设计的灉|性。尽余下的三个规范化层ơ有可能仅仅产生ơ数很少的变化,但它们仍然具有一些提高灵zL和效率的机?x)。下面是BCNF&4NF&5NF的定?比国内教材上|列的数学公式容易理解得多^_^)Q?br />  BCNF=3NFQ下面的规则Q?br />  每一个数据元素都完全依赖于键、整个键Q而且除依赖于q个键以外,不依赖于M其他数据元素?br />  4NF=3NF+下面的规则:(x)<br />  要把主键中拥有三个或更多外徏数据元素、切割格外键之间不存在约束的那些实体分解成两个或更多个实体?br />  5NF=4NF+下面的规则:(x)<br />  把主键中拥有三个或更多的外键数据元素Q且q些外键数据元素之间存在着U束的实体分解成为所有的U束都需要的多对多的关系?/p> <p>  当我们攀?NF的顶峰后Q再Ҏ(gu)实际需求情冉|q行“反向规范化”增加数据冗余,从而简化开发,提高查询速度。反向规范化是这样一个过E:(x)在定义了(jin)一个可靠的、完全规范化?jin)的数据l构之后Q你借助q个q程Q有选择地引入一些重复的数据Q以?j)进?gu)性能需求的实现。Steve Hoberman的“反向规范化生存指南”给如何适当增加冗余提供?jin)一套可计算的评分标准。通过考察每个关系?个问题,累加各个问题的得分之后,当得分大于等?0Ӟ我们对该关p进行反向规范化?/p> <p>  “反向规范化生存指南”的计分规则Q?br />  1.关系是什么类型的Q该问题定我们所分析的关pȝcd。父实体对于子实体具有什么样的关p?<br />  层次关系(20?<br />  同等关系(-10?<br />  定关系(-20?<br />  2.参与率是多少Q该问题定一个关pM的每个实体的参与性。换句话_(d)对于一个给定的父实体数|大概?x)有几个子实体数|父与子的关系接q“一对一”,我们对它q行反向规范化的Z(x)p大?br />  多达“一对五”的比率(20?<br />  多达“一对一䏀的比率(-10?<br />  过“一对一䏀的比率(-20?<br />  3.父实体中有多个数据元素<br />  于10个数据元?20?<br />  数据元素的数量介?0?0之间(-10?<br />  多于20个数据元?-20?<br />  4.使用率是多少Q当用户需要来自子的信息时Q通常情况下,它们是否q需要来自父的信息呢Q换句话_(d)q两个实体的耦合或相关程度如何?<br />  怺之间的关联很?30?<br />  怺之间的关联较弱或者没有关?-30?<br />  5.父实体时一个占位符吗:(x)在不q的来Q我们是否还打算向父实体加入更多的数据元素或关系Q如果答案是“不”,那么q行反向规范化的可行性就更强?br />  ?20?<br />  ?-20?<br />  6.变动Ҏ(gu)率是多少Q该问题是ؓ(f)?jin)确定,在同一旉周期内,两个实体的插入和更新的频度是否相q。如果其中一个实体很变化,而另一个实体却变动频繁Q那么,我们非常們֐于保持它们的规范化状态,把它们放在各自的表中?br />  相同(20?<br />  不同(-20?</p> <p>  “反向规范化生存指南”的使用Ҏ(gu)Q?br />  1)把模型中的关pL照优先排序<br />  2)选择一个关p?br />  3)对这个关pd{提?br />  4)如果得分{于或大?0Q就q行反向规范?br />  5)q回步骤二,直到完成所有的关系?/p> <p>  W九(ji)章:(x)抽象化安全指南和lg<br />  看过我的“浅谈数据库设计技?? ”的朋友应该q记得我丄W二个例子:(x)|上?sh)子商务q_上的商品信息表的设计。本章将我在上面例子中所用的Ҏ(gu)上升C(jin)理论阶段Q采用了(jin)面向对象的设计,所有商品的共有属性提取出来,抽象成一个超c,再加入一个表来记录各个不同实体之间的l节来实现超cȝzQ从而实现设计的灉|性。当出现下面两种条g的Q何场合,抽象化都是极其有用的Q?br />  设计需要永久维持下去:(x)要求以后可能的不修Ҏ(gu)据库设计<br />  需求可能发生变化:(x)应用E序的需求发生变化,而要求业务流E重l或q行功能升<br />  数据仓库Q当新的分类cd从源应用E序中传q来Ӟ我们无须Ҏ(gu)据仓库的设计q行M改动Q而只需在分cȝ型实体加入一个新行即?br />  元数据仓储库Q和数据仓库的要求类?/p> <p>  当然Q抽象化?x)大大增加工作量和开发的复杂度,而h们通常x的是非常短期的应用和眼前的成本,而不兛_(j)?yu)来的高得多的成本。所以,我非常赞同敏捯Y件开发这个观点:(x)在最初几乎不q行预先设计Q但是一旦需求发生变化,此时作ؓ(f)一名追求卓的E序员,应该从头审查整个架构设计Q在此次修改中设计出能够满日后cM修改的系l架构?/p> <p>  “抽象组件”就是小型的抽象模型片段Q在许多的徏模场?无论是什么行业、组l,甚至什么主体域的徏模场?中,它们都可被反复用。在键模阶段多次使用抽象化之后,你将开始看到出现的抽象化结构的势。这些“抽象组件”有如下的目的:(x)<br />  加快设计速度<br />  加快开发速度<br />  提供通用且有用的机构</p> <p>  W十章:(x)数据模型化技?br />  本章通过x如何改进逻辑和物理数据模型的视觉外观Q我们的设计超直接的应用E序需求。本章中讨论?jin)五个类别的化技巧:(x)<br />  逻辑数据元素排列技巧:(x)q些技巧是一个推荐的、对你的逻辑数据模型中的每一个实体的数据元素q行排序的方法?br />  物理数据元素排序技巧:(x)q些技巧关注数据模型中每一个实体的最?jng)_局?br />  实体布局技巧:(x)q些技巧关注数据模型中的每一个实体的最?jng)_局<br />  关系布局技巧:(x)q些技巧关注如何调整重叠的关系U条以及(qing)看v来穿(而不是绕q)(j)无关实体的关p?br />  吸引注意力的技巧:(x)q些技巧关注如何在我们的涉?qing)中H出的某些元素、实体或关系?/p> <p>  W十一章:(x)规划一个长盛不衰的数据建模生(dng)<br />  Ҏ(gu)据徏模者的十大忠告清单Q?br />  1)CQ灵zL、准性和背景<br />  2)建模只是你的工作的一部?br />  3)试其他角色<br />  4)?jin)?5/5规则Q?5%的时间将p?%的数据元素上<br />  5)数据建模从不令h厌烦(ch)Q如果你一直在做数据徏模工作,而且发现自己l常感到厌烦(ch)Q那么,你的该改变一下了(jin)。这可能不是数据建模领域本n令h厌烦(ch)Q而是你所在的特定的Q务、公司或行业不再令h兴奋。冒险一下,试着道一个不同的目或行业中q行数据建模工作吧!<br />  6)站在技术前?br />  7)量不要在模型上牉|感情因素Q徏模者必ȝ解,Z在评审过E中的意见ƈ不是针对模型的创,而是针对q个模型的内宏V即那句老话Q对事不对h?br />  8)让你的创造力展开膀Q在考虑记录数据需求和改进设计的新Ҏ(gu)Ӟ要紧可能有创造性。有创造性也许就意味着修改本书中的某些工具。这q可能意味着提出你自q?sh)子表格或其他工兗?br />  9)单纯的理论太昂贵?jin)?x)在设计活动过E中Q你要确保把q个观点牢记在心(j)。ؓ(f)q个应用E序掏腰包的部门和组l期望看到的是能看得着的实用结果?br />  10)成ؓ(f)一个了(jin)不v的会(x)讲故事的人:(x)作ؓ(f)一名数据徏模者,讲故事是工作的一个很重要的部分。ؓ(f)?jin)帮l教化和影响目l理以及(qing)Ҏ(gu)们行业缺乏理解的其他人,我们需要讲故事或趣闅R?/p> <p>  最后,我个得,Steve Hoberman所提出的“抽象组件”的观念和面向对象设计中的的“设计模式”非常类伹{即数据库专家在多次的数据徏模后Q将各个目中的cM部分抽象化,提取出特定的建模模型片段Q以后只需在新的项目中对这些模型片D늻化派生,卛_快速构建出适合于该目的数据库架构。不q,q些建模模型片段q没有统一QŞ成标准,目前也没有出版这cȝ书籍。本人正在陆lȝ自己在这斚w的经验,但是自知水^有限Q不敢在高h面前班门弄斧Q只希望自己日后陆箋发布的相x章能起到抛{引玉的作用,争取׃国的E序员率先统一出数据徏模领域的“设计模式”?/p> <img src ="http://www.aygfsteel.com/weibogao/aggbug/93122.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/weibogao/" target="_blank">weibogao</a> 2007-01-11 12:01 <a href="http://www.aygfsteel.com/weibogao/archive/2007/01/11/93122.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转《公文{发流E自定义的数据徏??/title><link>http://www.aygfsteel.com/weibogao/archive/2007/01/11/93120.html</link><dc:creator>weibogao</dc:creator><author>weibogao</author><pubDate>Thu, 11 Jan 2007 03:56:00 GMT</pubDate><guid>http://www.aygfsteel.com/weibogao/archive/2007/01/11/93120.html</guid><wfw:comment>http://www.aygfsteel.com/weibogao/comments/93120.html</wfw:comment><comments>http://www.aygfsteel.com/weibogao/archive/2007/01/11/93120.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/weibogao/comments/commentRss/93120.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/weibogao/services/trackbacks/93120.html</trackback:ping><description><![CDATA[ <h3 class="title"> </h3> <p>  开发比较复杂的企业多用L(fng)理信息系l?MIS)Q不可能不涉?qing)到pȝ内多个用户之间的数据文g的流转、审批等功能的开发。由于企业的需求L随着旉推移不断发生变化Q加之各个企业内部所讄的办公流E不相同,一套通用性比较好的管理信息系l应该能让系l管理员自己定义公文转发的流E?/p> <p>  管W者没有机?x)在已参与开发了(jin)的MIS中实现出文g转发程自定义的功能Q但是,早在2002q初曾深入思考过q方面的设计。当时由于某些原因不能公开自己的设计思\Q现在市(jng)面上已经有不MIS产品提供q样的功能,W者又已离职,所以是时候把我的设计思\整理出来Q和大家分n?/p> <p>  首先Q让我们分析需求,制定目标?/p> <p>  1)一般情况下Q企业内的公文{发、审Ҏ(gu)按部门或职位来{送,卛_岗不对h。例如:(x)某个程的某个环节需要胦(ch)务ȝ审批Q日后胦(ch)务ȝ换hQ该程应该不受影响。而且Q流E中某个环节可能出现某个部门中的M一人都能审批,或者需要该部门的所有h员共同审扏V?br />  2)程中{送,审批的公文一般分为文件和表单2U格式。文件格式的公文应该支持批处理,即一ơ可以{发多个文Ӟ审批时可以只退回其中某一个不合格的文Ӟ其他的文件可以{送到下一个环节l处理。表单格式的公文应该能让用户自己定义表单格式Q确定表单中的表V同理,表单也应该支持批处理?br />  3)程中处理公文的动作应该能让用户自己定义。这样一旦日后增加了(jin)新的处理动作Q也不用修改MISpȝ的底层数据徏模。当?dng)要实现新的处理动作,q是需要在业务逻辑层编写相应的代码Q不q和修改底层数据建模比v来,工作量要得多?br />  4)每个程的环节数不一定相同,应该能让用户讑֮环节敎ͼ指定公文{中每个环节的发送部门和接受部门Q处理模式,最长等待时间?br />  5)当待处理的公文发出后Q系l应该在{待旉中定期向该流E中下个环节的用??发出通知Q提醒该用户(??qing)时处理Q直臛_文已被处理。如果超出最长等待时_(d)公文q未被用??处理Q此ơ流E处理失败。企业管理层可能?x)要求记录相关信息,以便在日后业务流E重l?BPR)时参考?br />  6)某些企业׃Ҏ(gu)原因Q在某个程中要求实现跨环节处理。例如,该流E有6步,执行到第二个环节时要求处理后可以跌中间三个环节Q直接{到最后一个环节等候处理。其实,q种情况下,q不一定要在技术层面上实现其灵zL,q种特例毕竟是少数。用户只需定义一个新程Q把上面程的第1Q?Q?步复制加入进来,2个流E之间用程名来区分卛_。一个优U的系l架构设计师应该充分利用现有的工P不要什么都自行架设开发?/p> <p>  上面的需求对灉|性要求较高,抽象化程度较深,所以在表现层和业务逻辑层的开发量较大Q初期投资较多,不过开发完毕后估计不需对底层数据库修改Q即可满x后不断变化的公文{需求。如果不需要这么高的灵zL,可以按实际项目简化某些假设条件。下面按照上面的需求进行用?use case)分析和数据徏模?/p> <p>  1)׃程环节的发送方和接受方是对岗不对hQ我们应该先描画出整个企业的机构讄Q确定每个部门的权利职责。其中大的部门内可能有若q子部门Q每个子部门内又有不同职位,负责处理相应的事务。所以,可先建立一个树(wi)形关pȝ数据表来保存企业l构Q然后,采用权限表和用户l相l合的方式来保存每个部门每个职位的职能。这块的设计思\见我之前发布的“浅谈数据库设计技????”,我在下面直接l出大致的数据表l构Q?/p> <p>部门?Department_table)<br />名称    cd    U束条g    说明<br />Dp_id   int   无重复   cd标识Q主?br />Dp_name   varchar(50) 不允ؓ(f)I?cd名称Q不允许重复<br />Dp_father int 不允ؓ(f)I?该类别的父类别标识,如果是顶节点的话讑֮为某个唯一?br />Dp_layer varchar(6) 限定3?初始gؓ(f)000000 cd的先序遍历,主要为减检索数据库的次?/p> <p>功能?Function_table)<br />名称    cd    U束条g   说明<br />f_id int   无重复   功能标识Q主?br />f_name varchar(20) 不允ؓ(f)I?功能名称Q不允许重复<br />f_desc varchar(50) 允许为空 功能描述</p> <p>用户l表(User_group)<br />名称    cd     U束条g   说明<br />group_id int 无重?用户l标识,主键<br />group_name varchar(20) 不允ؓ(f)I?用户l名U?br />group_power varchar(100) 不允ؓ(f)I?用户l权限表Q内容ؓ(f)功能表f_id的集?/p> <p>用户?User_table)<br />名称    cd    U束条g   说明<br />user_id int 无重?用户标识Q主?br />user_name varchar(20) 无重?用户?br />user_pwd varchar(20) 不允ؓ(f)I?用户密码<br />user_type int 不允ؓ(f)I?所属用L(fng)标识Q和User_group.group_id兌</p> <p>  说明Q其中,按部门的不同职位讄不同权限的用L(fng)Q如某个用户lؓ(f)“市(jng)场部业务员”,该用L(fng)的用户可在流E“报销甌”中发送报销甌?/p> <p>  2)管程中的公文分ؓ(f)文g和表?U格式,但是每个文g/表单都应该有其唯一标识Q名U等属性。所以,我们把公文抽象化Q把q?U格式的公文的共有属性提取出来徏立一张公文表?/p> <p>公文?Document_table)<br />名称    cd    U束条g   说明<br />doc_id int 无重?公文标识Q主?br />doc_name varchar(50) 不允ؓ(f)I?公文名称<br />doc_type char(1) 不允ؓ(f)I?公文cd</p> <p>  doc_type字段用来辨别公文格式Q目前只?U格式,可设?”表C文件格式,?”表C单格式。估计未来新增公文格式不?x)太多,所以该字段只需一位字W。文件格式的公文一般是在文件内固定好格式,我们可用一个二q制的字D늛接保存整个文件的内容。文件格式的公文需要徏一个表来保存相关信息,其大致数据表如下Q?/p> <p>文g?File_table)<br />名称    cd    U束条g   说明<br />file_id int 无重?文g标识Q主?br />file_name varchar(50) 不允ؓ(f)I?文g名称<br />file_value binary 不允ؓ(f)I?文g内容<br />…?/p> <p>  表单格式的公文要让用戯己定义表单格式,定表单中的表项。有两种Ҏ(gu)来实玎ͼ(x)<br />  ①每当用户徏立一个新格式的表单时Q就新徏立一个表Q把用户输入的表单表当作该表的字段。这U方式的优点是表单查询速度较快方便Q业务逻辑层的开发量较小。缺Ҏ(gu)不太灉|Q如果企业所使用的不同格式的表单较多(>20U?Q整个数据库的结构显得比较؜乱,而且大部分表单中都有相同的字D,q样也增加了(jin)数据冗余。这U方式的数据建模如下Q?/p> <p>表单总表(Sheet_table)<br />名称    cd    U束条g   说明<br />sheet_id int 无重?表单标识Q主?br />sheet_name varchar(50) 不允ؓ(f)I?表单名称<br />table_name varchar(20) 不允ؓ(f)I?表单子表名,如Sub_table1/Sub_table2</p> <p>表单子表1(Sub_table1)<br />名称   cd   U束条g   说明<br />sub_id int 无重?表单子表标识Q主?br />option1 varchar 不允ؓ(f)I?表单表项1<br />option2 varchar 不允ؓ(f)I?表单表项2<br />option3 varchar 不允ؓ(f)I?表单表项3<br />…?/p> <p>表单子表2(Sub_table2)<br />名称   cd   U束条g   说明<br />sub_id int 无重?表单子表标识Q主?br />option1 varchar 不允ؓ(f)I?表单表项1<br />option2 varchar 不允ؓ(f)I?表单表项2<br />option3 varchar 不允ؓ(f)I?表单表项3<br />…?/p> <p>…?/p> <p>  ②对表单再进行一个抽象,把表单看成由若干个表单表Ҏ(gu)l合成的一个集合。这U方式的优点是相当灵z,用户建立新格式的表单时只用从已有表单表项中勾选出需要的表项卛_Q而且整个数据库结构清晎ͼ没有数据冗余。缺Ҏ(gu)开发比较复杂,工作量和上面相比高出不少Q而且表单查询速度较慢。下面是q种方式的数据徏模:(x)</p> <p>表单总表(Sheet_table)<br />名称    cd    U束条g   说明<br />sheet_id int 无重?表单标识Q主?br />sheet_name varchar(50) 不允ؓ(f)I?表单名称</p> <p>表单表项?Option_table)<br />名称   cd    U束条g   说明<br />op_id int 无重?表单表项标识Q主?br />op_name varchar(50) 不允ؓ(f)I?表单表项名称<br />op_length int 不允ؓ(f)I?表单表项长度<br />op_unit varchar(10) 允许为空 表单表项单位</p> <p>表单信息?Sheetinfo_table)<br />名称    cd    U束条g   说明<br />info_id int   无重?  表单信息标识Q主?br />sheet_id int 不允ؓ(f)I?所属表单标识,和Sheet_table.sheet_id兌<br />op_id  int 不允ؓ(f)I?表单表项标识Q和Option_table.op_id兌<br />info_value varchar() 不允ؓ(f)I?表单信息?/p> <p>  3)我们可以把公文{发的程抽象化,看作一个实体超cR徏表如下:(x)</p> <p>程?Flow_table)<br />名称     cd     U束条g   说明<br />flow_id int 无重?程标识Q主?br />flow_name varchar(50) 不允ؓ(f)I?程名称<br />flow_stepnum int 不允ؓ(f)I?程步数<br />flow_desc varchar(200) 允许为空 程描述</p> <p>  程中的每一步都可以抽象化成从发送方x受方的用例,其数据徏模大致如下:(x)</p> <p>处理动作?Action_table)<br />名称  cd     U束条g   说明<br />a_id int 无重?动作标识Q主?br />a_name varchar(20) 不允ؓ(f)I?动作名称<br />a_call varchar(50) 不允ؓ(f)I?动作所调用的模?br />a_desc varchar(200) 允许为空 动作描述</p> <p>  说明Q如果采用面向过E的开发方式,如纯脚本语言Q可以把每一个处理动作写成一个函敎ͼ调用a_call字段记录的函敎ͼ卛_完成相应处理动作。如果采用面向对象的开发方式,可以用COMlg来封装处理动作,则a_call用来记录相应的COMlg的接口方法。如果是?NET Framework环境下,可以采用Web服务的方式。当?dng)发送方、接受方以及(qing)公文标识是作入参数的?/p> <p>程环节?Step_table)<br />名称    cd   U束条g   说明<br />step_id int 无重?环节标识Q主?br />belong int 不允ؓ(f)I?所属流E标识,和Flow_table.flow_id兌<br />setp_order int 不允ؓ(f)I?所属流E的步骤ơ序<br />sender int 不允ؓ(f)I?发送方标识Q和User_group.group_id兌<br />receiver int 不允ؓ(f)I?接受Ҏ(gu)识,和User_group.group_id兌<br />a_id int 不允ؓ(f)I?处理动作标识Q和Action_table.a_id兌<br />a_type int 不允ؓ(f)I?接受Ҏ(gu)需的处理h?br />max_wait int 不允ؓ(f)I?最长等待时?br />wait_unit varchar(5) 不允ؓ(f)I?{待旉的单?/p> <p>  说明Qa_type用来定接受Ҏ(gu)需的处理h敎ͼ?”表C需同职位的所有h一起处理,?”表C只需该职位的L一名员工处理,?”表C需该职位的L两名员工一起处理,依次递推……一起处理的方式和处理动作有养I例如是投方式,数服从多数Q还是某人有一否x{等。可能针Ҏ(gu)些处理动作还得细化,q行相关的数据徏模,q里我就不细分下M(jin)?/p> <p>  4)下面分析公文转发的流E环节记录。此时相当于实例化一个流E环节的对象Q发送方和接受方应具体联pd理信息pȝ的某??用户Q而不是某个用L(fng)。每l过一环节Q我们除?jin)要保存q方面的信息Q还必须保存该环节所转发的公文,以及(qing)处理状况{信息。而且Q该环节所转发公文数量大于{于一Q所以可以参考我之前发布的“浅谈数据库设计技??”中的“简z的扚wm:n设计”,大致如下Q?/p> <p>程环节记录?Step_log)<br />名称   cd   U束条g   说明<br />log_id int 无重?环节记录标识Q主?br />step_id int 不允ؓ(f)I?环节标识Q和Step_table.step_id兌<br />sender varchar(100) 不允ؓ(f)I?发送用h识,相关用户l的User_table.user_id的集?br />receiver varchar(100) 不允ؓ(f)I?接受用户标识Q相关用L(fng)的User_table.user_id的集?br />doc_id int 不允ؓ(f)I?转发公文标识Q和Document_table.doc_id兌<br />batch_no int 不允ؓ(f)I?扚w转发公文~号Q同一程环节转发的batch_no相同<br />state char(1) 不允ؓ(f)I?处理状?br />sub_date datetime 不允ؓ(f)I?提交旉<br />res_date datetime 允许为空 处理回复旉<br />comment varchar(255) 允许为空   处理回复注释</p> <p>  说明Q?br />  ①同一程环节转发的batch_no和该批第一条入库的log_id相同。D例:(x)假设当前最大log_id?4Q接着某用户一ơ{发了(jin)3件公文,则批量插入的3条流E环节记录的batch_no都是65。之后另外一个用户通过某个程环节转发?jin)一件公文,再插入流E环节记录的batch_id?8?br />  ②state字段用来描述其流E环节所处的状态,是正待处理,已被处理通过Q已被处理驳回,q是出最长等待时间被pȝ自动收回{等。通过q个字段我们Ҏ(gu)受用户发出处理通知Q还可以可以很容易的查询出所有超出最长等待时间被pȝ自动收回的流E,以便企业理层在日后业务程重组(BPR)时参考?br />  ③如果某份公文在某个程中的某个环节被处理驳回,可以看作该公文在此次程中被驛_臌v始点Q最初发送用户可Ҏ(gu)处理回复注释修改公文后重新发送?/p> <p> <br />  ȝQ?br />  企业公文程自定义应该是把企业内已经固定?jin)的公文转发、审Ҏ(gu)E电(sh)子化Q实现高效的无纸化办公,对于非正式的口头讨论、商议、集?x)等商务zdq不适合。当企业累积?jin)一定数量的?sh)子化公文{发的记录后,可以在商业咨询专家和技术开发h员的协助下对其进行数据挖掘,分析出其中的低效、无用环节,q行优化重组Q最l提高整个企业的竞争力。作为技术开发h员,我们应该Ҏ(gu)企业实际q作情况、资金投入规模,选择当前时期最适合的技术解x案,切不可ؓ(f)?jin)展Cq技术实力,而把开发复杂化Q企业开发ƈ不是q求技术最先进Q而且最适合?/p> <img src ="http://www.aygfsteel.com/weibogao/aggbug/93120.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/weibogao/" target="_blank">weibogao</a> 2007-01-11 11:56 <a href="http://www.aygfsteel.com/weibogao/archive/2007/01/11/93120.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转《商品销售打折自定义的数据徏模?/title><link>http://www.aygfsteel.com/weibogao/archive/2007/01/11/93119.html</link><dc:creator>weibogao</dc:creator><author>weibogao</author><pubDate>Thu, 11 Jan 2007 03:50:00 GMT</pubDate><guid>http://www.aygfsteel.com/weibogao/archive/2007/01/11/93119.html</guid><wfw:comment>http://www.aygfsteel.com/weibogao/comments/93119.html</wfw:comment><comments>http://www.aygfsteel.com/weibogao/archive/2007/01/11/93119.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/weibogao/comments/commentRss/93119.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/weibogao/services/trackbacks/93119.html</trackback:ping><description><![CDATA[ <h3 class="title"> </h3> <p>  q期看了(jin)idilent的文章《用面向对象技术解军_品打折问题》,文后有读者提求:(x)如果不同商品的折扣不同怎么办? 或者有CN五十这U方式,或不同会(x)员等U的折扣不同?怎么处理Q”idilent认ؓ(f)打折q个问题q不是能够通过一个数据库的字D就可以解决的。有不同的会(x)员,不同的品,不同的销售计划,而这些也是在不停的不变化和增加的。而会(x)员和产品的打折,以及(qing)店庆(jin){打折,虽然都是折扣Q但是很难抽象成数据库中的一个字D|者几个字D,不用程序解冻I而希望只是通过改变数据库中的数据,在目前阶D实现v来可能还比较困难?/p> <p>  之前我曾参与q一个媄(jing)出U销售管理系l的目开发,负责其中的架构设计和数据建模工作Q尽最后该目׃某些客观原因而被攑ּQ但是该目中也有打折优惠这斚w的功能需求,我也思考过q一块的数据建模。其实,我们可以把商品销售打折这L(fng)商务规则分解成几个部分,分析各个部分之间的关p,从中扑և关键点,再将其泛化数据徏模,卛_实现让用戯己定义打折规则。下面开始分析商品销售打折的商业规则Q?/p> <p>  一套商品销售管理信息系l,必定存在下面两个实体Q顾客,商品Q打折这U商业规则一定是围绕着q两个实体以?qing)相互间的关p而制定的。回我们的购物l历Q打折的需求应该可以分ZU:(x)<br />  1)对特定商品的折扣一般有如下几种情况Q按售h(hun)q行一定百分比的打折;原h(hun)->特h(hun)(某个旉D内q行?的打折;捆绑优惠销?如购买某一(?U商品后卛_按较低的h或折扣购买另一(?U商??br />  2)寚w客的的打折方式一般采用会(x)员制Q即是按?x)员{在交Ҏ(gu)直接l与一定的折扣优惠Q或者在?x)员累积消费一定金额后l以一定比例的q点优惠Q该方式需要顾客办理会(x)员卡之类的n份标识卡?br />  3)Ҏ(gu)额的打折方式一般是֮消费后送出的限定最后用期限的代金券?/p> <p>  注意C面三大类折扣方式分解开来,都离不开商品Q所以这三种打折方式都是商品的共有属性,应该归入到商品表中。另外,一般大型超?jng)多拥有多个分店Q而且可能出现各个分店的打折规则略有不同的情况Q上面的三种打折规则得同相应的分店一一对应。最后,数据建模大致如下Q?/p> <p>店铺?Shop)<br />名称 cd U束条g 说明<br />shop_id int 无重?店铺标识Q主?br />shop_name varchar(40) 不允ؓ(f)I?店铺名称<br />shop_addr varchar(80) 不允ؓ(f)I?店铺地址<br />…?/p> <p>商品cd?Ware_type)<br />名称 cd U束条g 说明<br />type_id int 无重?商品cd标识Q主?br />type_name varchar(20) 不允ؓ(f)I?商品cd名称<br />father int 不允ؓ(f)I?该类别的父类别标识,如果是顶节点的话讑֮为某个唯一?br />layer char(6) 限定3?初始gؓ(f)000000 cd的先序遍历,主要为减检索数据库的次?/p> <p>商品?Ware)<br />名称 cd U束条g 说明<br />ware_id int 无重?商品标识Q主?br />ware_type int 不允ؓ(f)I?所属商品类别,和W(xu)are_type.type_id兌<br />ware_name varchar(40) 不允ؓ(f)I?商品名称<br />buy_price float 不允ؓ(f)I?q货?br />sell_price float 不允ؓ(f)I?销售h(hun)<br />d_type char(1) 不允ؓ(f)I?商品打折方式<br />m_type char(1) 不允ؓ(f)I??x)员打折方?br />has_coupon bit 默认gؓ(f)0 是否有代金券<br />…?/p> <p>  说明Q?br />  ①d_type用来辨别该商品的商品打折方式?0"表示该商品无商品折扣方式Q?1"表示该商品采用百分比打折方式Q?2"表示该商品采用特h折方式;"3"表示该商品采用捆l打折方式,是捆l打折规则中的必购商品;"4"表示该商品采用捆l打折方式,是捆l打折规则中的允购商品?br />  ②m_type用来辨别该商品的?x)员打折方式?0"表示该商品不参与?x)员折扣计算Q?1"表示该商品采取会(x)员百分比折扣方式Q?2"表示该商品采取会(x)员卡累积消费q点折扣方式?br />  ③has_coupon用来指明该商品是否有代金券?0"表示该商品无代金券;"1"反之?/p> <p>商品库存?Store_table)<br />名称 cd U束条g 说明<br />store_id int 无重?库存标识Q主?br />shop_id int 不允ؓ(f)I?店铺标识Q和Shop.shop_id兌<br />ware_id int 不允ؓ(f)I?商品标识Q和W(xu)are.ware_id兌<br />number int 默认gؓ(f)0 店铺库存数量<br />unit varchar(10) 不允ؓ(f)I?销售单?/p> <p>商品折扣规则?Discount)<br />名称 cd U束条g 说明<br />id int 无重?折扣规则标识Q主?br />s_id int 不允ؓ(f)I?店铺标识Q和Shop.shop_id兌<br />w_id int 不允ؓ(f)I?商品标识Q和W(xu)are.ware_id兌<br />d_value float 不允ؓ(f)I?打折数|用来记录癑ֈ比或特h(hun)<br />enddate datetime 不允ؓ(f)I?该规则的l止日期<br />number int 允许为空 该规则所允许的最大销?br />unit varchar(10) 允许为空 销售单?/p> <p>商品捆绑打折?Bind_discount)<br />名称 cd U束条g 说明<br />b_id int 无重?捆绑打折规则标识Q主?<br />shop_id int 不允ؓ(f)I?店铺标识Q和Shop.shop_id兌<br />1st_ware int 不允ؓ(f)I?必购的商品标识的集合Q和W(xu)are.ware_id兌<br />min_req int 默认gؓ(f)1 最必购数?br />2nd_ware int 不允ؓ(f)I?允购的商品标识的集合Q和W(xu)are.ware_id兌<br />max_buy int 默认gؓ(f)1 最大允购数?br />d_type char(1) 不允ؓ(f)I?打折方式Q是癑ֈ比方式还是特h?br />d_value float 不允ؓ(f)I?打折数|用来记录癑ֈ比或特h(hun)<br />enddate datetime 不允ؓ(f)I?该规则的l止日期<br />number int 允许为空 该规则所允许的最大销?br />unit varchar(10) 允许为空 销售单?/p> <p>  说明Q?st_ware用来记录必购商品的集合,min_req表示在必购商品集合内的最购买数量?nd_ware用来记录允购商品的集合,max_buy表示辑ֈ必购商品的最购买数量后Q所允许购买的允购商品的最大允购数量。D例说明:(x)某捆l销售规定,凡是购买?jin)某pd商品中的L1Ӟ卛_按特仯买允购商品中的Q??件。这U促(j)销方式大家都见q吧Q买二送一不过是其中的特例|了(jin)?/p> <p>?x)员{?Member_type)<br />名称 cd U束条g 说明<br />type_id int 无重??x)员{标识Q主?<br />s_id int 不允ؓ(f)I?店铺标识Q和Shop.shop_id兌<br />type_name varchar(10) 不允ؓ(f)I??x)员{名称<br />t_value float 不允ؓ(f)I?打折癑ֈ比或累积消费q点?br />condition float 不允ؓ(f)I?辑ֈ该等U所需累积的消贚w</p> <p>?x)员?Member)<br />名称 cd U束条g 说明<br />m_id int 无重??x)员标识Q主?<br />m_name varchar(10) 不允ؓ(f)I??x)员姓?br />type_id int 不允ؓ(f)I??x)员{标识Q和Member_type.type_id兌<br />score float 默认gؓ(f)0 ?x)员累积的消费积?br />…?/p> <p>代金券表(Coupon)<br />名称 cd U束条g 说明<br />c_id int 无重?代金券标识,主键 <br />c_name varchra(20) 不允ؓ(f)I?代金券姓?br />c_value float 不允ؓ(f)I?代金数额<br />condition float 不允ؓ(f)I?所需现金消费<br />enddate datetime 不允ؓ(f)I?代金券的l止日期</p> <p>  当然Q由于本人所认知的打折方式ƈ不全面,也没有和相关的业务h士深入讨q方面的问题。所以,上面的数据徏模ƈ不能保证覆盖现实商品销售中的的所有打折方式。不q,我相信,采用上面的数据徏模来定义打折规则Q覆盖率q是?0%以上的。根?5/5规则Q只要给我够的旉Q再加上专业人士的协助,不计开发成本的话,100%的覆盖率是可以达到的^-^</p> <p>  最后,׃每张购物清单都是由商品组成,而每U商品的折扣的计规则ƈ不一定完全相同,所以我认ؓ(f)在用面向对象的设计方法,设计计算折扣的组件时Q采用装?Decorator)模式比较适合?/p> <img src ="http://www.aygfsteel.com/weibogao/aggbug/93119.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/weibogao/" target="_blank">weibogao</a> 2007-01-11 11:50 <a href="http://www.aygfsteel.com/weibogao/archive/2007/01/11/93119.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转《Powerdesigner使用 ?/title><link>http://www.aygfsteel.com/weibogao/archive/2007/01/11/93111.html</link><dc:creator>weibogao</dc:creator><author>weibogao</author><pubDate>Thu, 11 Jan 2007 03:34:00 GMT</pubDate><guid>http://www.aygfsteel.com/weibogao/archive/2007/01/11/93111.html</guid><wfw:comment>http://www.aygfsteel.com/weibogao/comments/93111.html</wfw:comment><comments>http://www.aygfsteel.com/weibogao/archive/2007/01/11/93111.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/weibogao/comments/commentRss/93111.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/weibogao/services/trackbacks/93111.html</trackback:ping><description><![CDATA[ <p> <br />1.1业务规则的?Business Rule)<br />对于一些业务逻辑可能出现在多个数据表中,装成Business RuleQ这样便于业务逻辑的重C用,也便于业务逻辑的维护?/p> <p>Z(jin)便于l护业务逻辑Q可以考虑Business Rule和Domainsl合h使用。将业务Business Rule应用到Domains上,然后再把Domains应用到数据表的字D上?/p> <p>例如Q在拆迁目中,拆迁业务部分Q管理参C务部分,房源业务部分Q拆q合同部分的数据表中都有楼层q个字段Q因此先一个Business RuleQ然后定义一个DomainQ这L(fng)应的数据表的字段可以用这个Domain?jin)?/p> <p>1.2.自定义数据类?Domains)的?br />oralce提供?jin)一些内|的数据cdQ但是用户也可以Ҏ(gu)业务的需要,定义自定义的数据cd?/p> <p>在自定义数据cd里面包装业务逻辑?/p> <p>正如上面的房屋楼层,我们可以定义一个独立的数据cd(Domain)l护Q然后在相关数据表的</p> <p>字段上用这个自定义数据cd?/p> <p>一般在定义自己的数据类型时候,可以在oracle基本cd上定义,然后可以加上一些standard check或者Business Rules?/p> <p>比如Q在拆迁目中,面积cdq个字段在很多数据表都出C(jin)Q可以作Z个单独的数据cdcȝ护,定义一个?面积cd?DomainsQ包含的U类有:(x)0 --- 厅房面积,1 --- 使用面积,2 --- 单元面积,,3 --- d{面U?4 --- 分摊面积Q。而且׃Powerdesigner的提供关联作?q样便于当业务逻辑发生?jin)变动,能够很快查询出那些对象受到?jing)响?/p> <p>1.3序列?Sequence)的?<br />在powersigner的模型里面定义一堆了(jin)SequenceQ接下来的是要把他们和数据表的相兛_D关联v来,特别是那些用于多个数据表字段的Sequence?/p> <p>一个数据表原则上只允许一个字D用SequenceQƈ且在数据表的字段使用Sequence前,应该把该Sequenced到数据表的Extended Dependencies中?/p> <p>如果一个数据表?个字D|者更多字D用了(jin)SequenceQ那模型(g)查时?x)给出提CZ息?/p> <p>使用的规则一般是只能应用到数据表的主键字D上?/p> <p>主键字段?数据?“ID“或?“编号“构成?/p> <p>例如Q“房屋整合面U?数据表,那它的主键字D?房屋整合面积~号Q对应的Sequence?/p> <p>SEQ_房屋整合面积。其它数据表可能也用到?jin)这个SequenceQ那也需要在使用前设|引用关pR?/p> <p>Q在数据表的Extended Dependencies 上设|引用关p)(j)</p> <p>1.4 Oracle Package的?br />在Oracle Package里面可以定一些procedure Q但是Oracle包引用的数据库对象到底有哪些呢,q些信息手动l护h。特别是Oracle Package使用?jin)哪些数据表Q视图,以及(qing)Oracle Packag{信息徏议维护v来?/p> <p>1.5包的使用<br />PowerDesigner的包相当于文件夹。用户可以把它当作一个维护业务逻辑的容器。PowerDesigner包一般徏议按照业务模块来建立。如果模块需要细分,可以考虑建立PowerDesigner子包来完成?/p> <p>容器里保存的是模型对象的快捷方式。原始信息徏议不要放到容器里面。因为在要是把这些信息放到容器里Q在PowerDesigner的模型合q或者逆向工程Ӟq种方式的信息可能得不到l护?/p> <p>PowerDesigner的包下面的PhysicalDiagramQ徏议采用象ERWin的Subject Area那样Q按照某个主题或者业务角度的方式来组lPhysicalDiagram包含的对象,使得每个PhysicalDiagram的功能明?/p> <p> </p> <p>1.6.视图(View)的?br />视图一般是数据表或者视图上建立得来的(当然也可能引用了(jin)某个存储q程Q。一般视囄模型中应该维护视囄数据来源的引用信息?/p> <p>在我们现在的目中数据库模型没有对视图进行维护,为此需要在建立视图的Powerdesigner</p> <p>模型?/p> <p>我在Powerdesigner9.5环境下通过逆向工程不能够获得视?view)的脚本,通过修改相关?/p> <p>|参敎ͼq是不能够获得脚本?/p> <p>可以通过以下2Ҏ(gu)获得视图(view)的脚本?/p> <p>Ҏ(gu)1Q用powerdesigner8.0的逆向工程获得视图的脚本,然后在Powerdesigner9.5中把?/p> <p>囄模型合ƈq来Q这样就可以对视图进行维护了(jin)?/p> <p>Ҏ(gu)2Q用Erwin逆向工程获得视图的Erwin模型Q然后再把模型保存ؓ(f)ERXcd的文?/p> <p>在Powerdesigner9.5中导入该文gQ然后进行合q模型就可以?/p> <p>PowerDesigner的视图模型处理能力比较差Q不能构l护视图的依赖关p?也就是徏立视囑֯数据源的依赖关系)Q这一Ҏ(gu)显不如ERWin?/p> <p> </p> <p>1.7.同义词(synonymQ的使用<br />同义词相当于l数据库对象一个别名,提供?jin)位|和数据的独立性。在跨数据库用户讉K对象Ӟ可以考虑建立同义词结合权限分配,化数据库对象的访问?/p> <p> </p> <p>1.8Q数据表的?br />数据表的注释语句的更新?/p> <p>业务背景Q?/p> <p>在我们的目中,Erwin模型中的数据表的注释语句没有同步到Oracle数据库。现在需要更数据库中的数据表的注释语句?/p> <p>可能可以采取的实现方法:(x)</p> <p>Ҏ(gu)1QErwin直接正向工程Q但是从Erwin直接正向工程׃注释语句中有回RW号Q更C(x)p|?/p> <p>Ҏ(gu)2Q如果把Erwin模型转换成ؓ(f)powerdesigner模型再更新数据表的注释语句,q样可以避免回车符L(fng)问题Q按正常情况是可以行得通的Q但是由于Erwin模型中的逻辑模型和物理模型不一_(d)甚至它们出现的顺序不一_(d)q样获得powerdesigner模型׃正确?jin),生成的修?gu)据库的脚本也׃正确?jin)?/p> <p>实际采用的方法:(x)</p> <p>把Erwin模型转换成powerdesigner模型在Erwin中保存ؓ(f)ERXcdQ然后在PowerDesigner导入模型Q,q且把文件保存ؓ(f)PDMcdQXML格式Q,删除模型中的视图Qdomains,Business Rule,reference{信息,只留下相x据表本n的信息,然后把模型文件的后缀修改XMLQƈ且采用XMLSPY生成q个文g的DTD文gQ再采用Java~写?jin)一个基于SAX的程序去解析XML文gQ把各个数据表以?qing)字D늚注释语句提取出来Q然后更新数据库中数据表和字D늚注释语句Q这样就可以?jin)?/p> <p> </p> <p>1.9QERWin升到PowerDesigner的相关问?br />1.9.1 Domain的升U?br />从Erwin3.52升到PowerDesigner9.5ӞDomain信息和数据表的关联关pM(x)丢失Q需要手动重新添?者间的关pR当然可以通过~程修改PowerDesigner的模型文Ӟd2者之间的兌关系。一般的PowerDesigner模型文g较大Q只要有个几十张数据表肯定模型文件有1MBQ徏议采用SAX的方式添加信息?/p> <p>注意Q添加数据表字段使用的Domain时候,需要设|数据表对Domain的引用关p(也就是Extended DependenciesQ?/p> <p>1.9.2 Business Rule的升U?br />从Erwin3.52升到Powerdesigner9.5QBusiness Rule的表辑ּ(脚本)需要修改的Q把所有的</p> <p>Business Rule的表辑ּ中的@column 修改?COLUMN% </p> <p>具体实现的方式,可以直接在Powerdesigner9.5里面修改Q或者把模型保存为XML格式Q文件类?.pdmQ?通过UltraEdit或者XMLSpy{工h修改Q一个查找替换旧搞定?jin)。当然的注意</p> <p>只能修改<?XML:NAMESPACE PREFIX = C /?><c:businessrules></c:businessrules>里面的内容,否则?x)修改一些不应该修改的地斏V?/p> <p>同Domain一P从Erwin3.52升到PowerDesigner9.5ӞBusiness信息和数据表的关联关pM?x)丢失。如果Business Rule 不是太多手动修改模型文g?/p> <p> </p> <p>1.9.3.Sequence的升U?br />.Sequence的升U徏议采用和Domain的方式,~程实现l护?/p> <p>1.9.4.物理囄升<br />从Erwin3.52升到Powerdesigner9.5Q物理图同样能够倒入Powerdesigner9.5中,但是Powerdesigner9.5的升U功能有些问题:(x)在生成的物理图中数据表的信息有些问题Q物理图中的数据表的字段昄不完全,而且很多时候数据表字段的类型都不能昄完全。我使用java采用sax的方式把升后的模型文gq行解析Q然后重新生成物理图中数据表的位|信息(数据表的2个坐标:(x)左上角坐标,右下角坐标)(j)Q另外根据业务需要可以生成自qPowerdesigner9.5包ƈ且可以创建物理图Q把数据表添加到物理图上?/p> <p> </p> <p>1.9.5.其他说明<br />从Erwin3.52升到Powerdesigner9.5Q我写了(jin)一些javaE序解决?jin)相关问题,如果哪位同行遇到怼的问?/p> <p>可以交流一下?/p> <p>2Q关于powerdesigner中的数据l构的变更管?br />目前拆迁目中数据结构的有些失控Q在l合powerdesigner包的概念的基׃提出如下一些徏议?/p> <p>2.1Q数据结构按照业务模块进行维?br />模型中所有的数据l构都在一个文件中Q而且在顶层文件夹中各个业务模块维护的是数据结构的快捷方式?/p> <p>2.2Q数据结构按照其生命周期q行分类理?br />在各个业务模块的包下面徏立如下的包:(x)</p> <p>2.2.1临时试数据l构Q?br />是一些当前业务模块测试时使用的数据结构,可以随时被删?/p> <p>2.2.2讨论中数据结构:(x)<br />是数据结构处于讨ZQ还没有定下来?/p> <p>2.2.3需要更新的数据l构Q?br />是数据结构已l确定下来,但是q没有更新到数据库中?/p> <p>2.2.4正式数据l构Q?br />在数据库中被业务正常使用的数据结?/p> <p>2.2.5作废中的数据l构Q?br />在数据库中以前被业务正常使用Q现在已l不再用,但是q没有进?/p> <p>被作废的数据表中数据的迁U,没有完全作废的数据结构。如果要把这些数据结构进行作废,</p> <p>需要先q行数据q移Q以?qing)其他相兛_理?/p> <p>2.2.6已经作废的数据结构:(x)<br />在数据库已经不再被用的业务数据表,相关的数据迁Udl完成,但是数据表还没有删除Q?/p> <p>相关的文档没有更新?/p> <img src ="http://www.aygfsteel.com/weibogao/aggbug/93111.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/weibogao/" target="_blank">weibogao</a> 2007-01-11 11:34 <a href="http://www.aygfsteel.com/weibogao/archive/2007/01/11/93111.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于SQLServer的若q注意事?/title><link>http://www.aygfsteel.com/weibogao/archive/2006/07/12/57854.html</link><dc:creator>weibogao</dc:creator><author>weibogao</author><pubDate>Wed, 12 Jul 2006 11:28:00 GMT</pubDate><guid>http://www.aygfsteel.com/weibogao/archive/2006/07/12/57854.html</guid><wfw:comment>http://www.aygfsteel.com/weibogao/comments/57854.html</wfw:comment><comments>http://www.aygfsteel.com/weibogao/archive/2006/07/12/57854.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/weibogao/comments/commentRss/57854.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/weibogao/services/trackbacks/57854.html</trackback:ping><description><![CDATA[如果你正在负责一个基于SQL Server的项? 或者你刚刚接触SQL Server, 你都有可能要面(f)一些数据库性能的问? q篇文章?x)?f)你提供一些有用的指导( 其中大多C可以用于其它的DBMS) . <br /><br />在这? 我不打算介绍使用SQL Server的窍? 也不能提供一个包ȝ病的Ҏ(gu), 我所做的是ȝ一些经?---关于如何形成一个好的设? q些l验来自我过dq中l受的教? 一直来, 我看到许多同L(fng)设计错误被一ơ又一ơ的重复. <br /><br /><strong>你了(jin)解你的工具吗? </strong><br /><br />不要轻视q一? q是我在q篇文章中讲q的最关键的一? 也许你也看到有很多的SQL ServerE序员没有掌握全部的T-SQL命o(h)和SQL Server提供的那些有用的工具. <br /><br />“什? 我要费一个月的时间来学习(fn)那些我永q也不会(x)用到的SQL命o(h)? ? 你也怼(x)q样? 对的, 你不需要这样做. 但是你应该用一个周末浏览所有的T-SQL命o(h). 在这? 你的d是了(jin)? 来, 当你设计一个查询时, 你会(x)记v? “对? q里有一个命令可以完全实现我需要的功能? 于是, 到MSDN查看q个命o(h)的确切语? <br /><br /><strong>不要使用游标</strong><br /><br />让我再重复一? 不要使用游标. 如果你想破坏整个pȝ的性能的话, 它们倒是你最有效的首选办? 大多数的初学者都使用游标, 而没有意识到它们Ҏ(gu)能造成的媄(jing)? 它们占用内存, q用它们那些不可思议的方式锁定表, 另外, 它们直就像蜗? 而最p糕的是, 它们可以使你的DBA所能做的一切性能优化{于没做. 不知你是否知道每执行一ơFETCHq于执行一ơSELECT命o(h)? q意味着如果你的游标?0000条记? 它将执行10000ơSELECT! 如果你用一lSELECT, UPDATE或者DELETE来完成相应的工作, 那将有效率的? <br /><br />初学者一般认Z用游标是一U比较熟(zhn)和舒适的~程方式, 可很不幸, q会(x)Dp糕的性能. 昄, SQL的M目的是你要实C? 而不是怎样实现. <br /><br />我曾l用T-SQL重写?jin)一个基于游标的存储q程, 那个表只?00,000条记? 原来的存储过E用?0分钟才执行完? 而新的存储过E只用了(jin)10U钟. 在这? 我想你应该可以看C个不U职的程序员I竟在干?jin)什?<br /><br />我们可以写一个小E序来取得和处理数据q且更新数据? q样做有时会(x)更有? C: 对于循环, T-SQL无能为力. <br /><br />我再重新提醒一? 使用游标没有好处. 除了(jin)DBA的工作外, 我从来没有看到过使用游标可以有效的完成Q何工? <br /><br /><strong>规范化你的数据表</strong><br /><br />Z么不规范化数据库? 大概有两个借口: Z性能的考虑和纯_因为懒? 至于W二? 你迟早得为此付出代h(hun). 而关于性能的问? 你不需要优化根本就不慢的东? 我经常看C些程序员“反规范化”数据库, 他们的理由是“原来的设计太慢?jin)? 可结果却常常是他们让pȝ更慢? DBMS被设计用来处理规范数据库? 因此, C: 按照规范化的要求设计数据? <br /><br /><strong>不要使用SELECT *</strong><br /><br />q点不太Ҏ(gu)做到, 我太?jin)解? 因ؓ(f)我自己就l常q样q? 可是, 如果在SELECT中指定你所需要的? 那将?x)带来以下的好? <br /><br />1 减少内存耗费和网l的带宽<br /><br />2 你可以得到更安全的设?br /><br />3 l查询优化器Z(x)从烦(ch)引读取所有需要的?br /><br /><strong>?jin)解你将要对数据q行的操?/strong><br /><br />Z的数据库创徏一个健壮的索引, 那可是功德一? 可要做到q一点简直就是一门艺? 每当你ؓ(f)一个表d一个烦(ch)? SELECT?x)更快?jin), 可INSERT和DELETE却大大的变慢? 因ؓ(f)创徏?jin)维护?ch)引需要许多额外的工作. 昄, q里问题的关键是: 你要对这张表q行什么样的操? q个问题不太好把? 特别是涉?qing)DELETE和UPDATE? 因ؓ(f)q些语句l常在WHERE部分包含SELECT命o(h). <br /><br /><strong>不要l“性别”列创徏索引</strong><br /><br />首先, 我们必须?jin)解索引是如何加速对表的讉K? 你可以将索引理解为基于一定的标准上对表进行划分的一U方? 如果你给cM于“性别”这L(fng)列创Z(jin)一个烦(ch)? 你仅仅是表划分Z部分: 男和? 你在处理一个有1,000,000条记录的? q样的划分有什么意? C: l护索引是比较费时的. 当你设计索引? 请遵循这L(fng)规则: Ҏ(gu)列可能包含不同内容的数目从多到少排列, 比如: 姓名+省䆾+性别. <br /><br /><strong>使用事务</strong><br /><br />请用事? 特别是当查询比较耗时. 如果pȝ出现问题, q样做会(x)救你一命的. 一般有些经验的E序员都有体?----你经怼(x)到一些不可预料的情况?x)导致存储过E崩? <br /><br /><strong>心(j)死锁</strong><br /><br />按照一定的ơ序来访问你的表. 如果你先锁住表A, 再锁住表B, 那么在所有的存储q程中都要按照这个顺序来锁定它们. 如果? 不经意的) 某个存储q程中先锁定表B, 再锁定表A, q可能就?x)导致一个死? 如果锁定序没有被预先详l的设计? 死锁是不太容易被发现? <br /><br /><strong>不要打开大的数据?/strong><br /><br />在CSDN技术论坛中 :) , 一个经常被提出的问题是: 我怎样才能q速的?00000条记录添加到ComboBox? q是不对? 你不能也不需要这样做. 很简? 你的用户要浏?00000条记录才能找到需要的记录, 他一定会(x)诅咒你的. 在这? 你需要的是一个更好的UI, 你需要ؓ(f)你的用户昄不超q?00?00条记? <br /><br /><strong>不要使用服务器端游标</strong><br /><br />与服务器端游标比h, 客户端游标可以减服务器和网l的pȝ开销, q且q减锁定时? <br /><br /><strong>使用参数查询</strong><br /><br />有时, 我在CSDN技术论坛看到类DL(fng)问题: “SELECT * FROM a WHERE a.id='A'B, 因ؓ(f)单引h询发生异? 我该怎么? ? 而普遍的回答? 用两个单引号代替单引? q是错误? q样L不治? 因ؓ(f)你还?x)在其他一些字W上遇到q样的问? 更何况这样会(x)D严重的bug, 除此以外, q样做还?x)SQL Server的缓冲系l无法发挥应有的作用. 使用参数查询, 釜底抽薪, q些问题l统不存在了(jin). <br /><br /><strong>在程序编码时使用大数据量的数据库</strong><br /><br />E序员在开发中使用的测试数据库一般数据量都不? 可经常的是最l用L(fng)数据量都很大. 我们通常的做法是不对? 原因很简? 现在盘不是很贵, 可ؓ(f)什么性能问题却要{到已经无可挽回的时候才被注意呢? <br /><br /><strong>不要使用INSERT导入大批的数?/strong><br /><br />请不要这样做, 除非那是必须? 使用UTS或者BCP, q样你可以一举而兼得灵zL和速度. <br /><br /><strong>注意时问题</strong><br /><br />查询数据库时, 一般数据库的缺省都比较?yu)? 比如15U或?0U? 而有些查询运行时间要比这? 特别是当数据库的数据量不断变大时. <br /><br /><strong>不要忽略同时修改同一记录的问?/strong><br /><br />有时? 两个用户?x)同时修改同一记录, q样, 后一个修改者修改了(jin)前一个修改者的操作, 某些更新׃(x)丢失. 处理q种情况不是很难: 创徏一个timestamp字段, 在写入前(g)查它, 如果允许, 合q修? 如果存在冲突, 提示用户. <br /><br /><strong>在细节表中插入纪录时, 不要在主表执行SELECT MAX(ID)</strong><br /><br />q是一个普遍的错误, 当两个用户在同一旉插入数据? q会(x)D错误. 你可以用SCOPE_IDENTITY, IDENT_CURRENT和@@IDENTITY. 如果可能, 不要使用@@IDENTITY, 因ؓ(f)在有触发器的情况? 它会(x)引v一些问? 详见q里的讨? . <br /><br /><strong>避免列设ؓ(f)NULLable</strong><br /><br />如果可能的话, 你应该避免将列设为NULLable. pȝ?x)?f)NULLable列的每一行分配一个额外的字节, 查询时会(x)带来更多的系l开销. 另外, 列设ؓ(f)NULLable使编码变得复? 因ؓ(f)每一ơ访问这些列旉必须先进行检? <br /><br />我ƈ不是说NULLS是麻?ch)的?gu), 管有些栯? 我认为如果你的业务规则中允许“空数据? 那么, 列设ؓ(f)NULLable有时?x)发挥很好的作? 但是, 如果在类g面的情况中用NULLable, 那简直就是自讨苦? <br /><br />CustomerName1<br />CustomerAddress1<br />CustomerEmail1<br />CustomerName2<br />CustomerAddress2<br />CustomerEmail3<br />CustomerName1<br />CustomerAddress2<br />CustomerEmail3<br /><br />如果出现q种情况, 你需要规范化你的表了(jin). <br /><br /><strong>量不要使用TEXT数据cd</strong><br /><br />除非你用TEXT处理一个很大的数据, 否则不要使用? 因ؓ(f)它不易于查询, 速度? 用的不好q会(x)费大量的空? 一般的, VARCHAR可以更好的处理你的数? <br /><br /><strong>量不要使用临时?/strong><br /><br />量不要使用临时? 除非你必这样做. 一般用子查询可以代替临时? 使用临时表会(x)带来pȝ开销, 如果你是用COM+q行~程, 它还?x)给你带来很大的ȝ?ch), 因ؓ(f)COM+使用数据库连接池而(f)时表却自始至l都存在. SQL Server提供?jin)一些替代方? 比如Table数据cd. <br /><br /><strong>学会(x)分析查询</strong><br /><br />SQL Server查询分析器是你的好伙? 通过它你可以?jin)解查询和?ch)引是如何影响性能? <br /><br /><strong>使用参照完整?/strong><br /><br />定义d, 唯一性约束和外键, q样做可以节U大量的旉. <br /><br /><img src ="http://www.aygfsteel.com/weibogao/aggbug/57854.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/weibogao/" target="_blank">weibogao</a> 2006-07-12 19:28 <a href="http://www.aygfsteel.com/weibogao/archive/2006/07/12/57854.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <a href="http://www.aygfsteel.com/" title="狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频">狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频</a> </div> </footer> վ֩ģ壺 <a href="http://" target="_blank">ڽ</a>| <a href="http://" target="_blank">ߺ</a>| <a href="http://" target="_blank">ɽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">º</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">Ϫ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ݸ</a>| <a href="http://" target="_blank">ϳ</a>| <a href="http://" target="_blank">÷</a>| <a href="http://" target="_blank">ຣʡ</a>| <a href="http://" target="_blank">Ӱ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ɳ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ƽ</a>| <a href="http://" target="_blank">ؿ˹</a>| <a href="http://" target="_blank">䶨</a>| <a href="http://" target="_blank">ʡ</a>| <a href="http://" target="_blank">齭</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ƽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">̩</a>| <a href="http://" target="_blank">ߺ</a>| <a href="http://" target="_blank">ˮ</a>| <a href="http://" target="_blank">ĵ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>