??xml version="1.0" encoding="utf-8" standalone="yes"?> Index or table scans(索引或者表扫描)Q可能意味着需要更好的或者额外的索引?/p>
Bookmark Lookups(书签查找)Q考虑修改当前的聚集烦引,使用复盖索引Q限制SELECT语句中的字段数量?/p>
Filter(qo)Q在WHERE从句中移除用到的M函数Q不要在SQL语句中包含视图,可能需要额外的索引?/p>
Sort(排序)Q数据是否真的需要排序?可否使用索引来避免排序?在客L排序是否会更加有效率Q?/p>
查看SQL Server囑Ş执行计划Ӟ可以查找的非常有用的一个东西就是查询优化器如何为给定的查询使用索引来从表中获取数据。通过查看是否有用到烦引,以及索引如何被用,都有助于判断当前的烦引是否得查询执行得可能的快?/p>
鼠标移到图形执行计划上的表?以及它的图标)上面Q就会弹Z个窗口,从它上面可以看到一些信息。这些信息让你知道是否有用到索引来从表中获取数据Q以及它是如何用的。这些信息包括: · Table Scan(表扫?Q如果看到这个信息,p明数据表上没有聚集烦引,或者查询优化器没有使用索引来查找。意卌料表的每一行都被检查到。如果资料表相对较小的话Q表扫描可以非常快速,有时甚至快过使用索引?/p>
因此Q当看到有执行表扫描ӞW一件要做的事就是看看数据表有多数据行。如果不是太多的话,那么表扫描可能提供了最好的M效能。但如果数据表大的话Q表扫描极可能需要长旉来完成,查询效能大受媄响。在q种情况下,需要仔l研IӞ为数据表增加一个适当的烦引用于这个查询?/p>
假设你发现某查询使用了表扫描Q有一个合适的非聚集烦引,但它没有用到。这意味着什么呢Qؓ什么这个烦引没有用到呢Q如果需要获得的数据量相Ҏ据表大小来说非常大,或者数据选择性不?意味着同一个字D中重复的值很?Q表扫描l常会比索引扫描快。例如,如果一个数据表?0000个数据行Q查询返?000行,如果q个表没有聚集烦引的话,那么表扫描将比用一个非聚集索引更快。或者如果数据表?0000个数据行Q且同一个字D?WHERE条g句有用到q个字段)上有1000W重复的数据Q表扫描也会比用非聚集索引更快?/p>
查看囑Ş执行计划上的数据表上的弹出式H口Ӟh?#8221;预估的资料行?Estimated Row Count)”。这个数字是查询优化器作出的多少个数据行会被q回的最x。如果执行了表扫描且”预估的数据行?#8221;数值很高的话,意味着q回的记录数很多Q查询优化器认ؓ执行表扫描比使用可用的非聚集索引更快?/p>
· Index Seek(索引查找)Q烦引查找意味着查询优化器用了数据表上的非聚集索引来查找数据。性能通常会很快,其是当只有数的数据行被返回时?/p>
· Clustered Index Seek(聚集索引查找)Q这指查询优化器使用了数据表上的聚集索引来查找数据,性能很快。实际上Q这是SQL Server能做的最快的索引查找cd?/p>
· Clustered Index Scan(聚集索引扫描)Q聚集烦引扫描与表扫描相|不同的是聚集索引扫描是在一个徏有聚集烦引的数据表上执行的。和一般的表扫描一P聚集索引扫描可能表明存在效能问题。一般来_有两U原因会引此聚集索引扫描的执行。第一个原因,相对于数据表上的整体数据行数目,可能需要获取太多的数据行。查?#8221;预估的数据行数量(Estimated Row Count)”可以Ҏ加以验证。第二个原因Q可能是׃WHERE条g句中用到的字D选择性不高。在M情况下,与标准的表扫描不同,聚集索引扫描q不会LL找数据表中的所有数据,所以聚集烦引扫描一般都会比标准的表扫描要快。通常来说Q要聚集烦引扫描改成聚集烦引查找,你唯一能做的是重写查询语句Q让语句限制性更多,从而返回更的数据行?/p>
l大多数情况下,查询优化器会对连接进行分析,按最有效率的序Q用最有效率的q接cd来对数据表进行连接。但q不L如此。在囑Ş执行计划中你可以看到代表查询所使用到的各种不同q接cd的图标。此外,每个q接图标都有两个头指向它。指向连接图标的上面的箭头代表该q接的外部表Q下面的头则代表这个连接的内部表。箭头的另一头则指向被连接的数据表名?/p>
你常怼在图形执行计划上看到标识?#8221;书签查找(Bookmark Lookup)”的图标。书{查扄当常见。书{查扄本质是告诉你查询处理器必M数据表或者聚集烦引中来查扑֮所需要的数据行,而不是从非聚集烦引中直接d?/p>
Hadoop
是一个开源的可运行于大规模集上的分布式q行~程框架Q由于分布式存储对于分布式编E来说是必不可少的,q个框架中还包含了一个分布式文gpȝ
HDFS( Hadoop Distributed File System )。也许到目前为止QHadoop
q不是那么广Zh知,其最新的版本号也仅仅?0.16Q距?1.0 g都还有很长的一D距,但提?Hadoop 一脉相承的另外两个开源项?
Nutch ?Lucene ( 三者的创始人都?Doug Cutting ),那绝Ҏ大名鼎鼎。Lucene 是一个用 Java
开发的开源高性能全文索工具包Q它不是一个完整的应用E序Q而是一套简单易用的 API 。在全世界范围内Q已有无数的软gpȝQWeb |站Z
Lucene 实现了全文检索功能,后来 Doug Cutting 又开创了W一个开源的 Web 搜烦引擎(http://www.nutch.org)
Nutch, 它在 Lucene 的基上增加了|络爬虫和一些和 Web 相关的功能,一些解析各cL档格式的插g{,此外QNutch
中还包含了一个分布式文gpȝ用于存储数据。从 Nutch 0.8.0 版本之后QDoug Cutting ?Nutch
中的分布式文件系l以及实?MapReduce 法的代码独立出来Ş成了一个新的开源项 Hadoop。Nutch 也演化ؓZ Lucene
全文索以?Hadoop 分布式计^台的一个开源搜索引擎?
Z
Hadoop,你可以轻村֜~写可处理v量数据的分布式ƈ行程序,q将其运行于由成百上千个l点l成的大规模计算机集上。从目前的情冉|
看,Hadoop 注定会有一个辉煌的未来Q?云计?是目前灸手可热的技术名词,全球各大 IT 公司都在投资和推q这U新一代的计算模式Q?
Hadoop 又被其中几家主要的公司用作其"云计?环境中的重要基础软gQ如:雅虎正在借助 Hadoop 开源^台的力量Ҏ Google,
除了资助 Hadoop 开发团队外Q还在开发基?Hadoop 的开源项?Pig, q是一个专注于量数据集分析的分布式计程序。Amazon
公司Z Hadoop 推出?Amazon S3 ( Amazon Simple Storage Service
)Q提供可靠,快速,可扩展的|络存储服务Q以及一个商用的云计^?Amazon EC2 ( Amazon Elastic Compute
Cloud )。在 IBM 公司的云计算目--"蓝云计划"中,Hadoop 也是其中重要的基软g。Google
正在跟IBM合作Q共同推q基?Hadoop 的云计算?
q接~程方式的变?
在摩定律的作用下,以前E序员根本不用考虑计算机的性能会跟不上软g的发展,因ؓU每?18 个月QCPU
的主频就会增加一倍,性能也将提升一倍,软gҎ不用做Q何改变,可以n受免费的性能提升。然而,׃晶体电路已l逐渐接近其物理上的性能极限Q摩?
定律?2005 q左叛_始失效了Qhcd也不能期待单?CPU 的速度每隔 18 个月q一倍,为我们提供越来越快的计算性能。Intel,
AMD, IBM {芯片厂商开始从多核q个角度来挖?CPU
的性能潜力Q多核时代以及互联网时代的到来,软g~程方式发生重大变革Q基于多核的多线Eƈ发编E以及基于大规模计算机集的分布式ƈ行编E是来?
件性能提升的主要途径?
许多U编E方式的重大变化带来一ơY件的q发危机Q因为我们传l的软g方式基本上是单指令单数据的序执行Q这U顺序执行十分符合h
cȝ思考习惯,却与q发q行~程格格不入。基于集的分布式ƈ行编E能够让软g与数据同时运行在q成一个网l的许多台计机?q里的每一台计机均可?
是一台普通的 PC 机。这L分布式ƈ行环境的最大优Ҏ可以很容易的通过增加计算机来扩充新的计算l点Qƈ由此获得不可思议的v量计能?
同时又具有相当强的容错能力,一批计结点失效也不会影响计算的正常进行以及结果的正确性。Google 是q么做的Q他们用了叫做
MapReduce 的ƈ行编E模型进行分布式q行~程Q运行在叫做 GFS ( Google File System
)的分布式文gpȝ上,为全球亿万用h供搜索服务?
Hadoop 实现?Google ?MapReduce ~程模型Q提供了单易用的~程接口Q也提供了它自己的分布式文gpȝ
HDFS,?Google 不同的是QHadoop
是开源的QQ何h都可以用这个框架来q行q行~程。如果说分布式ƈ行编E的隑ֺ以让普通程序员望而生畏的话,开源的 Hadoop
的出现极大的降低了它的门槛,d本文Q你会发现基?Hadoop
~程非常单,无须Mq行开发经验,你也可以L的开发出分布式的q行E序Qƈ让其令h难以|信地同时运行在数百台机器上Q然后在短时间内完成量数据
的计。你可能会觉得你不可能会拥有数百台机器来q行你的q行E序Q而事实上Q随着"云计?的普及,M人都可以L获得q样的v量计能力。例如现?
Amazon 公司的云计算q_ Amazon EC2
已经提供了这U按需计算的租用服务,有兴的读者可以去了解一下,q篇pd文章的第三部分将有所介绍?
掌握一点分布式q行~程的知识对来的程序员是必不可的QHadoop 是如此的便好用,何不试一下呢Q也怽已经急不可耐的惌一下基?
Hadoop 的编E是怎么回事了,但毕竟这U编E模型与传统的顺序程序大不相同,掌握一点基知识才能更好地理解基?Hadoop
的分布式q行E序是如何编写和q行的。因此本文会先介l一?MapReduce 的计模型,Hadoop 中的分布式文件系l?HDFS,
Hadoop 是如何实现ƈ行计的Q然后才介绍如何安装和部|?Hadoop 框架Q以及如何运?Hadoop E序?
MapReduce 计算模型
MapReduce ?Google 公司的核心计模型,它将复杂的运行于大规模集上的ƈ行计过E高度的抽象C两个函数QMap ?
Reduce, q是一个o人惊讶的单却又威力巨大的模型。适合?MapReduce 来处理的数据?或Q?有一个基本要?
待处理的数据集可以分解成许多的数据集,而且每一个小数据集都可以完全q行地进行处理?
?1. MapReduce 计算程
图一说明了用 MapReduce 来处理大数据集的q程, q个 MapReduce
的计过E简而言之,是大数据集分解ؓ成百上千的小数据集,每个(或若q个)数据集分别由集群中的一个结?一般就是一台普通的计算?q行处理q生
成中间结果,然后q些中间l果又由大量的结点进行合q? 形成最l结果?
计算模型的核心是 Map ?Reduce 两个函数Q这两个函数q戯责实玎ͼ功能是按一定的映射规则输入的 <key, value> 对{换成另一个或一?<key, value> 对输出?
表一 Map ?Reduce 函数
函数 输入 输出 说明
Map <k1, v1> List(<k2,v2>) 1. 小数据集进一步解析成一?<key,value> 对,输入 Map 函数中进行处理?
2. 每一个输入的 <k1,v1> 会输Z?<k2,v2>?<k2,v2> 是计的中间l果?nbsp;
Reduce <k2,List(v2)> <k3,v3> 输入的中间结?<k2,List(v2)> 中的 List(v2) 表示是一批属于同一?k2 ?value
以一个计文本文件中每个单词出现的次数的E序ZQ?lt;k1,v1> 可以?<行在文g中的偏移位置,
文g中的一?gt;Q经 Map 函数映射之后QŞ成一批中间结?<单词Q出现次?gt;, ?Reduce
函数则可以对中间l果q行处理Q将相同单词的出现次数进行篏加,得到每个单词的ȝ出现ơ数?
Z MapReduce 计算模型~写分布式ƈ行程序非常简单,E序员的主要~码工作是实现 Map ?Reduce
函数Q其它的q行~程中的U种复杂问题Q如分布式存储,工作调度Q负载^衡,定w处理Q网l通信{,均由 MapReduce 框架(比如 Hadoop
)负责处理Q程序员完全不用操心?
?集群上的q行计算
MapReduce 计算模型非常适合在大量计机l成的大规模集群上ƈ行运行。图一中的每一?Map d和每一?Reduce d均可以同时运行于一个单独的计算l点上,可想而知其运效率是很高的,那么q样的ƈ行计是如何做到的呢Q?
数据分布存储
Hadoop 中的分布式文件系l?HDFS ׃个管理结?( NameNode )和N个数据结?( DataNode
)l成Q每个结点均是一台普通的计算机。在使用上同我们熟悉的单Z的文件系l非常类|一样可以徏目录Q创建,复制Q删除文Ӟ查看文g内容{。但其底
层实C是把文g切割?BlockQ然后这?Block 分散地存储于不同?DataNode 上,每个 Block q可以复制数份存储于不同?
DataNode 上,辑ֈ定w容灾之目的。NameNode 则是整个 HDFS
的核心,它通过l护一些数据结构,记录了每一个文件被切割成了多少?BlockQ这?Block 可以从哪?DataNode 中获得,各个
DataNode 的状态等重要信息。如果你想了解更多的关于 HDFS 的信息,可进一步阅d考资料: [url]The Hadoop
Distributed File System:Architecture and Design [/url]
分布式ƈ行计?
Hadoop 中有一个作Z控的 JobTrackerQ用于调度和理其它?TaskTracker, JobTracker
可以q行于集中M台计机上。TaskTracker 负责执行dQ必运行于 DataNode 上,?DataNode
既是数据存储l点Q也是计结炏V?JobTracker ?Map d?Reduce d分发l空闲的 TaskTracker,
让这些Q务ƈ行运行,q负责监控Q务的q行情况。如果某一?TaskTracker 出故障了QJobTracker
会将其负责的d转交l另一个空闲的 TaskTracker 重新q行?
本地计算
数据存储在哪一台计机上,qq台计算行这部分数据的计,q样可以减少数据在网l上的传输,降低对网l带宽的需求。在 Hadoop
q样的基于集的分布式ƈ行系l中Q计结点可以很方便地扩充,而因它所能够提供的计能力近乎是无限的,但是由是数据需要在不同的计机之间动Q故|?
l带宽变成了瓉Q是非常宝贵的,“本地计算”是最有效的一U节U网l带宽的手段Q业界把qŞ容ؓ“Ud计算比移动数据更l济”?
?2. 分布存储与ƈ行计?
d_度
把原始大数据集切割成数据集Ӟ通常让小数据集小于或{于 HDFS 中一?Block 的大?~省?
64M)Q这栯够保证一个小数据集位于一台计机上,便于本地计算。有 M 个小数据集待处理Q就启动 M ?Map dQ注意这 M ?Map
d分布?N 台计机上ƈ行运行,Reduce d的数?R 则可qh定?
Partition
?Map d输出的中间结果按 key 的范围划分成 R ? R 是预先定义的 Reduce d的个?Q划分时通常使用 hash
函数? hash(key) mod RQ这样可以保证某一D范围内?keyQ一定是׃?Reduce d来处理,可以?Reduce
的过E?
Combine
?partition 之前Q还可以对中间结果先?combineQ即中间结果中有相?key?<key, value>
对合q成一寏Vcombine 的过E与 Reduce 的过E类|很多情况下就可以直接使用 Reduce 函数Q但 combine 是作?
Map d的一部分Q在执行?Map 函数后紧接着执行的。Combine 能够减少中间l果?<key, value>
对的数目Q从而减网l流量?
Reduce d?Map dl点取中间结?
Map d的中间结果在做完 Combine ?Partition 之后Q以文g形式存于本地盘。中间结果文件的位置会通知L
JobTracker, JobTracker 再通知 Reduce d到哪一?DataNode 上去取中间结果。注意所有的 Map
d产生中间l果均按?Key 用同一?Hash 函数划分成了 R 份,R ?Reduce d各自负责一D?Key 区间。每?
Reduce 需要向许多?Map dl点取得落在其负责的 Key 区间内的中间l果Q然后执?Reduce 函数QŞ成一个最l的l果文g?
d道
?R ?Reduce dQ就会有 R 个最l结果,很多情况下这 R 个最l结果ƈ不需要合q成一个最l结果。因 R 个最l结果又可以做ؓ另一个计Q务的输入Q开始另一个ƈ行计Q务?
?Hadoop 初体?
Hadoop 支持 Linux ?Windows 操作pȝ, 但其官方|站声明 Hadoop 的分布式操作?Windows
上未做严格测试,只把 Windows 作ؓ Hadoop 的开发^台。在 Windows 环境上的安装步骤如下( Linux
q_cMQ且更简单一?:
(1)?Windows 下,需要先安装 Cgywin, 安装 Cgywin 时注意一定要选择安装 openssh (?Net
category )。安装完成之后,?Cgywin 的安装目录如 c:\cygwin\bin 加到pȝ环境变量 PATH 中,q是因ؓq行
Hadoop 要执行一?linux 环境下的脚本和命令?
(2)安装 Java 1.5.xQƈ?JAVA_HOME 环境变量讄?Java 的安装根目录?C:\Program Files\Java\jdk1.5.0_01?
(3)?Hadoop 官方|站[url] http://hadoop.apache.org[/url]下蝲Hadoop Core, 最新的E_版本?0.16.0. 下载后的安装包解压C个目录,本文假定解压?c:\hadoop-0.16.0?
4)修改 conf/hadoop-env.sh 文gQ在其中讄 JAVA_HOME 环境变量Q?export
JAVA_HOME="C:\Program Files\Java\jdk1.5.0_01” (因ؓ路径?Program Files
中间有空|一定要用双引号\径引h)
xQ一切就l,可以q行 Hadoop 了。以下的q行q程Q需要启?cygwin, q入模拟 Linux 环境。在下蝲?Hadoop
Core 包中Q带有几个示例程序ƈ且已l打包成?hadoop-0.16.0-examples.jar。其中有一?WordCount
E序Q功能是l计一Ҏ本文件中各个单词出现的次敎ͼ我们先来看看怎么q行q个E序。Hadoop 共有三种q行模式:
单机(非分布式)模式Q伪分布式运行模式,分布式运行模式,其中前两U运行模式体C?Hadoop
分布式计的优势Qƈ没有什么实际意义,但对E序的测试及调试很有帮助Q我们先从这两种模式入手Q了解基?Hadoop
的分布式q行E序是如何编写和q行的?
单机(非分布式)模式
q种模式在一台单Zq行Q没有分布式文gpȝQ而是直接d本地操作pȝ的文件系l?
代码清单1
注意事项Q运?bin/hadoop jar hadoop-0.16.0-examples.jar wordcount test-in
test-out Ӟ务必注意W一个参数是 jar, 不是 -jar, 当你?-jar
Ӟ不会告诉你是参数错了Q报告出来的错误信息是:Exception in thread "main"
java.lang.NoClassDefFoundError: org/apache/hadoop/util/ProgramDriver,
W者当时以为是 classpath 的设|问题,费了不时间。通过分析 bin/hadoop 脚本可知Q?jar q不?bin/hadoop
脚本定义的参敎ͼ此脚本会?-jar 作ؓ Java 的参敎ͼJava ?jar 参数表示执行一?Jar 文g(q个 Jar
文g必须是一个可执行?Jar,卛_ MANIFEST 中定义了ȝ), 此时外部定义?classpath 是不起作用的Q因而会抛出
java.lang.NoClassDefFoundError 异常。?jar ?bin/hadoop 脚本定义的参敎ͼ会调?Hadoop
自己的一个工L RunJarQ这个工L也能够执行一?Jar 文gQƈ且外部定义的 classpath 有效?
伪分布式q行模式
q种模式也是在一台单Zq行Q但用不同的 Java q程模仿分布式运行中的各cȝ?( NameNode, DataNode,
JobTracker, TaskTracker, Secondary NameNode )Q请注意分布式运行中的这几个l点的区别:
从分布式存储的角度来_集群中的l点׃?NameNode 和若q个 DataNode l成, 另有一?Secondary
NameNode 作ؓ NameNode 的备份。从分布式应用的角度来说Q集中的结点由一?JobTracker 和若q个
TaskTracker l成QJobTracker 负责d的调度,TaskTracker 负责q行执行d。TaskTracker 必须q行?
DataNode 上,q样便于数据的本地计。JobTracker ?NameNode 则无d同一台机器上?
(1) 按代码清?修改 conf/hadoop-site.xml。注?conf/hadoop-default.xml 中是
Hadoop ~省的参敎ͼ你可以通过L文g了解 Hadoop 中有哪些参数可供配置Q但不要修改此文件。可通过修改
conf/hadoop-site.xml 改变~省参数|此文件中讄的参数g覆盖 conf/hadoop-default.xml
的同名参数?
代码清单 2
参数 fs.default.name 指定 NameNode ?IP 地址和端口号。缺省值是 file:///, 表示使用本地文gpȝ, 用于单机非分布式模式。此处我们指定用运行于本机 localhost 上的 NameNode?
参数 mapred.job.tracker 指定 JobTracker ?IP 地址和端口号。缺省值是 local, 表示在本地同一
Java q程内执?JobTracker ?TaskTracker, 用于单机非分布式模式。此处我们指定用运行于本机 localhost
上的 JobTracker ( 用一个单独的 Java q程?JobTracker )?
参数 dfs.replication 指定 HDFS 中每?Block 被复制的ơ数Qv数据冗余备䆾的作用。在典型的生产系l中Q这个数常常讄??
(2)配置 SSH,如代码清?所C?
代码清单 3
配置完后Q执行一?ssh localhost, 认你的机器可以?SSH q接Qƈ且连接时不需要手工输入密码?
(3)格式化一个新的分布式文gpȝ, 如代码清?所C?
代码清单 4
(4) 启动 hadoop q程, 如代码清?所C。控制台上的输出信息应该昄启动?namenode, datanode,
secondary namenode, jobtracker, tasktracker。启动完成之后,通过 ps –ef
应该可以看到启动?个新?java q程?
代码清单 5
(5) q行 wordcount 应用, 如代码清?所C?
代码清单 6
故障诊断
(1) 执行 $ bin/start-all.sh 启动 Hadoop q程后,会启??java q程, 同时会在 /tmp
目录下创Z?pid 文g记录q些q程 ID 受通过q五个文Ӟ可以得知 namenode, datanode, secondary
namenode, jobtracker, tasktracker 分别对应于哪一?Java q程。当你觉?Hadoop
工作不正常时Q可以首先查看这5?java q程是否在正常运行?
(2) 使用 web 接口。访?http://localhost:50030 可以查看 JobTracker 的运行状态。访?
http://localhost:50060 可以查看 TaskTracker 的运行状态。访?http://localhost:50070
可以查看 NameNode 以及整个分布式文件系l的状态,览分布式文件系l中的文件以?log {?
(3) 查看 ${HADOOP_HOME}/logs 目录下的 log 文gQnamenode, datanode, secondary
namenode, jobtracker, tasktracker 各有一个对应的 log 文gQ每一ơ运行的计算d也有对应?log
文g。分析这?log 文g有助于找到故障原因?
l束?
现在Q你已经了解?MapReduce 计算模型Q分布式文gpȝ HDFSQ分布式q行计算{的基本原理, q且有了一个可以运行的 Hadoop 环境Q运行了一个基?Hadoop 的ƈ行程序?
]]>
有时在多表连接的查询中,头的另一头指向的q不是一个数据表Q而是另一个连接。如果将鼠标Ud指向外部q接与内部连接的头上,可以看C个弹出式H口Q告诉你有多数据行被发送至q个q接来进行处理。外部表应该L比内部表含有更少的数据行。如果不是,则说明查询优化器所选择的连接顺序可能不正确(下面是关于这个话题的更多信息)?/p>
首先Q让我们来看看连接类型。SQL Server可以使用三种不同的技术来q接资料表:嵌套循环(nested loop)Q散?hash)Q以及合q?merge)。一般来_嵌套循环是最快的q接cdQ但如果不可能用嵌套@环的话,则会用到散列或者合q作为合适的q接cd。两者都比嵌套@环连接慢?/p>
当连接大表时Q则合ƈq接可能是最佳选项Q而非嵌套循环q接。唯一的明这一点的方式是对两者都q行试以查看哪一个最有效率?/p>
如果你怀疑某个查询速度慢的原因可能是因为它所使用的连接类型不理想Q那么你可以使用q接提示来复盖查询优化器的选择。在使用q接提示之前Q你需要花费一些时间去了解一下每U连接类型以及它们的工作方式。这是一个复杂的话题Q超Z本文的讨围?/p>
查询优化器选择最有效率的q接cd来连接数据表。例如,嵌套循环q接的外部表应该是连接的两个表中较小的那个表。散列连接也是一P它的外部表应该是较小的那个表。如果你觉得查询优化器选择的连接顺序是错误的,可以使用q接提示来复盖它?/p>
打比方说Q如果一个查询语句的SELECT,JOIN以及WHERE子句中的所有字D,都不存在于那个用来定位符合查询条件的数据行的非聚集烦引中Q那么查询优化器׃得不做额外的工作在数据表或聚集烦引中查找那些满q个查询语句的字Dc?/p>
另一U引起书{查扄原因是用了SELECT *。由于在l大多情况下它会q回比你实际所需更多的数据,所以应该永不用SELECT *.
从性能斚w来说Q书{查找是不理想的。因为它会请求额外的I/O开销在字D中查找以返回所需的数据行?/p>
如果认ؓ书签查找防碍了查询的性能Q那么有四种选择可以用来避免它:可以建立WHERE子句会用到的聚集索引Q利用烦引交集的优势Q徏立覆盖的非聚集烦引,或?如果是SQL Server 2000/2005企业版的?可以建立索引视图。如果这些都不可能,或者用它们中的Q何一个都会耗用比书{查找更多的资源Q那么书{查扑ְ是最佳的选择了。[
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/xiao_hn/archive/2009/06/11/4259628.aspx
]]>
?span style="font: 7pt Times New Roman"> ?/strong>Q每?/span>SQL语句
?span style="font: 7pt Times New Roman"> 隔离Q事?/span>
?/strong>
?/span>
q发问题
丢失更新
未确认的dQ脏读)
不一致的分析Q非重复读)Q多ơ读取相同的数据Q行Q不一_其他用户更改updateQ?/span>
qd读:多次d有不存在和新增的数据Q其他用h?/span>insert或删?/span>deleteQ?/span>
隔离U别
隔离U别 |
脏读 |
不可重复d |
qd |
说明 |
未提交读(read uncommitted) |
?/span> |
?/span> |
?/span> |
如果其他事务更新Q不是否提交,立即执行 |
提交?span>(read committed默认) |
?/span> |
?/span> |
?/span> |
d提交q的数据。如果其他事务更新没提交Q则{待 |
可重复读(repeatable read) |
?/span> |
?/span> |
?/span> |
查询期间Q不允许其他事务update |
可串行读(serializable) |
?/span> |
?/span> |
?/span> |
查询期间Q不允许其他事务insert或delete |
提交?/span>
假设存在?/span>AQ如下所C?/span>
A1 |
A2 |
A3 |
11 |
21 |
31 |
12 |
22 |
32 |
打开查询分析器ƈ打开两个q接Q分别输入如下两个事务:
--事务?/span>
SET TRANSACTION ISOLATION LEVEL READ Committed
begin tran
update A set A2 = 20 where A1 = 11
waitfor delay '00:
rollback tran
--事务?/span>
SET TRANSACTION ISOLATION LEVEL READ Committed
select * from A where A1 = 11
如果先运行事务ⅠQ然后紧接着q行事务Ⅱ,则事务Ⅱ要等?/span>10U钟Q?/span>一个连接在修改数据块时别的q接也不能查询这个数据块Q直到解?/strong>。反之亦Ӟȝ时候不能写和修?/span>Q?/span>
如果把事务Ⅱ改ؓ如下
SET TRANSACTION ISOLATION LEVEL READ UNCommitted
select * from A where A1 = 11
那么事务Ⅱ不需{待Q立x行(可以看出READ UNCommitted事务select不对数据发出׃n?/strong>Q?/span>
?/strong>Q?/span>(q里主要讲解 ׃n?/strong> ?/span> 排他?/strong> 两种l常用到?strong style="background-color: #99ff99; color: black">?/strong>)
׃n?/strong>主要是ؓ了共享读Q?/span>selectQ,如果存在事务Q一个或多个Q拥有对表中数据Q关?strong style="background-color: #99ff99; color: black">?/strong>数据的多,?strong style="background-color: #99ff99; color: black">?/strong>的粒度而定Q的׃n?/strong>Q不允许?strong style="background-color: #99ff99; color: black">?/strong>定的数据q行更新(update)Q从?/strong>的角度讲Q即不允怺务获取排?strong style="background-color: #99ff99; color: black">?/strong>Q要{到所有的׃n?/strong>都释放掉Q。反之,如果事务Ҏ据已l具有排?strong style="background-color: #99ff99; color: black">?/strong>Q只能有一个)Q其他的事务׃能对?/strong>定的数据获取׃n?/strong>和排?strong style="background-color: #99ff99; color: black">?/strong>Q即排他?/strong>与共?strong style="background-color: #99ff99; color: black">?/strong>不能兼容Q更多信息请查看?/strong>兼容?/span>Q,在此特别一?/span> ?/strong>定的数据 Q因为有的资料上讲解?/span>“一个连接写的时候,另一个连接可以写”Q实际上写的q种情况是各个连接的d的数据不是相同的行,也就是说各个q接?/strong>定的数据不同?/span>
Ҏ以上分析Q我们ȝ为六个字?#8220;׃n读,排他?/span>”?/span>
了解?strong style="background-color: #99ff99; color: black">?/strong>的情况之后,又涉及到一个问题。事务究竟要保持?/strong>多久?/span>?
一般来_׃n?/strong>?strong style="background-color: #99ff99; color: black">?/strong>定时间与事务?strong style="background-color: #ffff66; color: black">隔离U别有关Q如?strong style="background-color: #ffff66; color: black">隔离U别?/span>Read Committed的默认别,只在d(select)的期间保?strong style="background-color: #99ff99; color: black">?/strong>定,卛_查询出数据以后就释放?strong style="background-color: #99ff99; color: black">?/strong>Q如?strong style="background-color: #ffff66; color: black">隔离U别为更高的Repeatable read?/span>SerializableQ直C务结束才释放?/strong>。另说明Q如?/span>select语句中指定了HoldLock提示Q则也要{到事务l束才释?strong style="background-color: #99ff99; color: black">?/strong>?/span>
排他?/strong>直到事务l束才释放?/span>
做出了以上分析,现在我们可能会存在这L疑问Q到底在执行SQL语句的时候发Z么样?strong style="background-color: #99ff99; color: black">?/strong>呢,q就׃务的隔离U别军_了。一般情况,读语?/span>(select)发出׃n?/strong>Q写语句(update,insert,delete)发出排他?/strong>。但是,如果q样不能满我们的要求怎么办呢Q有没有更多选择呢,别急,SQLserver为我们提供了?/strong>定提C的概念?/span>
?/strong>定提C对SQL语句q行特别指定Q这个指定将覆盖事务?strong style="background-color: #ffff66; color: black">隔离U别。下面对各个?/strong>定提C分别予以介l(更多资料h?/span>SQLserver的联机帮助)Q笔者做Z以下分类?/span>
cd1
?span style="font: 7pt Times New Roman">
READUNCOMMITTEDQ不发出?/strong>?span style="font: 7pt Times New Roman"> READCOMMITTEDQ发出共?strong style="background-color: #99ff99; color: black">?/strong>Q保持到dl束
?span style="font: 7pt Times New Roman"> REPEATABLEREADQ发出共?strong style="background-color: #99ff99; color: black">?/strong>Q保持到事务l束
?span style="font: 7pt Times New Roman"> SERIALIZABLEQ发出共?strong style="background-color: #99ff99; color: black">?/strong>Q保持到事务l束
cd2
?span style="font: 7pt Times New Roman"> NOLOCKQ不发出?/strong>。等同于READUNCOMMITTED
?span style="font: 7pt Times New Roman"> HOLDLOCKQ发出共?strong style="background-color: #99ff99; color: black">?/strong>Q保持到事务l束。等同于SERIALIZABLE
?span style="font: 7pt Times New Roman"> XLOCKQ发出排?strong style="background-color: #99ff99; color: black">?/strong>Q保持到事务l束?/span>
?span style="font: 7pt Times New Roman"> UPDLOCKQ发出更?strong style="background-color: #99ff99; color: black">?/strong>Q保持到事务事务l束。(更新?/strong>Q不d别的事物Q允许别的事物读数据Q即更新?/strong>可与׃n?/strong>兼容Q,但他保自上ơ读取数据后数据没有被更?/span>Q?/span>
?span style="font: 7pt Times New Roman"> READPASTQ发出共?strong style="background-color: #99ff99; color: black">?/strong>Q但跌?/strong>定行Q它不会被阻塞?span style="color: red">适用条gQ提交读?strong style="background-color: #ffff66; color: black">隔离U别Q行U?strong style="background-color: #99ff99; color: black">?/strong>Q?/span>select语句中?/span>
cd3
?span style="font: 7pt Times New Roman"> ROWLOCKQ行U?strong style="background-color: #99ff99; color: black">?/strong>
?span style="font: 7pt Times New Roman"> PAGLOCKQ页U?strong style="background-color: #99ff99; color: black">?/strong>
?span style="font: 7pt Times New Roman"> TABLOCKQ表?/strong>
?span style="font: 7pt Times New Roman"> TABLOCKXQ表排他?/strong>
讲解?strong style="background-color: #99ff99; color: black">?/strong>后,下面l合一个具体实例,具体看一?strong style="background-color: #99ff99; color: black">?/strong>的用?/span>
在很多系l中Q经怼遇到q种情况Q要保持一个编L唯一Q如会计软g中的凭证的编受一U编L处理是这LQ把表中的最大编号保存到表中Q然后在q个~号上篏加,形成新的~号。这个过E对q发处理要求非常高,下面我们来模拟q个q程Q看如何保持~号的唯一性?/span>
新徏一张表code来保存凭证的最大编受字D如下:~号:bh(numeric(18,0)),凭证表名pinzheng(varchar(50))
假设表中有这L一条记录:
Bh |
Pinzheng |
18000 |
会计凭证 |
新徏一个存储过E来生成新的凭证~号Q如下:
CREATE PROCEDURE up_getbh AS
Begin Tran
Declare @numnewbh numeric(18,0)
select @numnewbh = bh FROM code WITH (UPDLOCK,ROWLOCK) where pinzheng = '会计凭证'
set @numnewbh = @numnewbh + 1
update code set bh = @numnewbh where pinzheng = '会计凭证'
print @numnewbh
Commit tran
GO
然后Q打开查询分析器,q多开几个q接Q笔者开?/span>8个连接,模拟?/span>8个h同时q发Q读者可以开更多的连接进行试验)Q把cM以下q样的语句复制到每个q接H口中,
declare @i numeric(18,0)
set @i = 1
while @i = 1
Begin
if getdate() > '2004-07-22 14:23' --讑֮一个时_到此旉同时执行upgetbh存储q程
set @i = 0
end
exec up_getbh
然后Q接q运行各个连接,?/span>2004-7-22 14Q?/span>23 q一刻,各个q接同时q行up_getbh。从q行l果可以看出q接序出现18001开始个数字Qƈ没有重号或丢L现象?/span>
分析Q由?/span>up_getbh中的select语句使用了更?strong style="background-color: #99ff99; color: black">?/strong>Q因更新?/strong>之间不能兼容Q所以各个连接要{到所有其他的q接释放?strong style="background-color: #99ff99; color: black">?/strong>才能执行Q而更?strong style="background-color: #99ff99; color: black">?/strong>的释放要{到事务l束Q这样就不会发生号出错的现象了?/span>
/* 建立试?Card,代表一个真实的卡库,供用h?用户要从里边选出一个未使用的卡Q也是F_Flag=0的卡Q给用户注册Q更新F_Name,F_Time,F_Flag字段. 假如出现两个用户同时更新一张卡的情况,是不能容忍的Q也是我们所说的数据不一致行?/
create table Card(F_CardNO varchar(20),F_Name varchar(20),F_Flag bit,F_Time datetime)
Go
insert Card(F_CardNo,F_Flag) select '1111-1111',0
insert Card(F_CardNo,F_Flag) select '1111-1112',0
insert Card(F_CardNo,F_Flag) select '1111-1113',0
insert Card(F_CardNo,F_Flag) select '1111-1114',0
insert Card(F_CardNo,F_Flag) select '1111-1115',0
insert Card(F_CardNo,F_Flag) select '1111-1116',0
insert Card(F_CardNo,F_Flag) select '1111-1117',0
insert Card(F_CardNo,F_Flag) select '1111-1118',0
insert Card(F_CardNo,F_Flag) select '1111-1119',0
insert Card(F_CardNo,F_Flag) select '1111-1110',0
Go
-- 下边是我们经怋用的更新Ҏ如下:
declare @CardNo varchar(20)
Begin Tran
-- 选择一张未使用的卡
select top 1 @CardNo=F_CardNo
from Card where F_Flag=0
-- 延迟50U,模拟q发讉K.
waitfor delay '000:00:50'
-- 把刚才选择出来的卡q行注册.
update Card
set F_Name=user,
F_Time=getdate(),
F_Flag=1
where F_CardNo=@CardNo
commit
问题:假如我们在同一H口执行同一D代码,但是L了waitfor delay子句.两边执行完毕?我们发现管执行了两ơ注册,但是只注册了一张卡Q也是两个人注册了同一张卡.
悲观锁定解决Ҏ
-- 我们只要对上边的代码做微的改变可以实现悲观的锁定.
declare @CardNo varchar(20)
Begin Tran
-- 选择一张未使用的卡
select top 1 @CardNo=F_CardNo
from Card with (UPDLOCK) where F_Flag=0
-- 延迟50U,模拟q发讉K.
waitfor delay '000:00:50'
-- 把刚才选择出来的卡q行注册.
update Card
set F_Name=user,
F_Time=getdate(),
F_Flag=1
where F_CardNo=@CardNo
commit
注重其中的区别了?with(updlock),是的,我们在查询的时候用了with (UPDLOCK)选项,在查询记录的时候我们就对记录加上了更新?表示我们卛_Ҏ记录q行更新.注重更新锁和׃n锁是不冲H的,也就是其他用戯可以查询此表的内?但是和更新锁和排它锁是冲H的.所以其他的更新用户׃d.假如我们在另外一个窗口执行此代码,同样不加waifor delay子句.两边执行完毕?我们发现成功的注册了两张?可能我们已经发现了悲观锁定的~点:当一个用戯行更新的事务的时?其他更新用户必须排队{待,即那个用户更新的不是同一条记?
乐观锁定解决Ҏ
-- 首先我们在Card表里边加上一列F_TimeStamp ?该列是varbinary(8)cd.但是在更新的时候这个g自动增长.
alter table Card add F_TimeStamp timestamp not null
-- 悲观锁定
declare @CardNo varchar(20)
declare @timestamp varbinary(8)
declare @rowcount int
Begin Tran
-- 取得卡号和原始的旉戛_?br />
select top 1 @CardNo=F_CardNo,
@timestamp=F_TimeStamp
from Card
where F_Flag=0
-- 延迟50U,模拟q发讉K.
waitfor delay '000:00:50'
-- 注册?但是要比较时间戳是否发生了变?假如没有发生变化.更新成功.假如发生变化,更新p|.
update Card
set F_Name=user,
F_Time=getdate(),
F_Flag=1
where F_CardNo=@CardNo and F_TimeStamp=@timestamp
set @rowcount=@@rowcount
if @rowcount=1
begin
print '更新成功!'
commit
end
else if @rowcount=0
begin
if exists(select 1 from Card where F_CardNo=@CardNo)
begin
print '此卡已经被另外一个用h册!'
rollback tran
end
else
begin
print 'q不存在此卡!'
rollback tran
end
end
在另外一个窗口里Ҏ行没有waitfor的代?注册成功?q回原来的窗?我们׃发现到时间后它显C的提示是此卡以被另外一个用h册的提示.很明?q样我们也可以避免两个用户同时注册一张卡的现象的出现.同时,使用q种Ҏ的另外一个好处是没有使用更新?q样增加的系l的q发处理能力.
上边我具体介l了乐观锁定和悲观锁定的使用Ҏ,在实际生产环境里?假如q发量不?我们完全可以使用悲观锁定的方?因ؓq种Ҏ使用h非常方便和简?但是假如pȝ的ƈ发非常大的话,悲观锁定会带来非常大的性能问题,所以我们就要选择乐观锁定的方?
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/gudenren/archive/2009/07/31/4397291.aspx
对于Oracle的一些基本知识要加强学习Q我从网上抄了三个h对这个题目的见解下来Q供已参考?/font>
NESTED LOOP:
对于被连接的数据子集较小的情况,嵌套循环q接是个较好的选择。在嵌套循环中,?br /> 表被外表驱动Q外表返回的每一行都要在内表中检索找C它匹配的行,因此整个查询q回 的结果集不能太大Q大? 万不适合Q,要把q回子集较小表的作ؓ外表QCBO 默认外表?br /> 驱动表)Q而且在内表的q接字段上一定要有烦引。当然也可以用ORDERED 提示来改变CBO 默认的驱动表Q用USE_NL(table_name1 table_name2)可是强制CBO 执行嵌套循环q接?br /> HASH JOIN : 散列q接是CBO 做大数据集连接时的常用方式,优化器用两个表中较的表(或数?br /> 源)利用q接键在内存中徏立散列表Q然后扫描较大的表ƈ探测散列表,扑և与散列表匚w 的行?br /> q种方式适用于较的表完全可以放于内存中的情况,q样L本就是访问两个表的成 本之和。但是在表很大的情况下ƈ不能完全攑օ内存Q这时优化器会将它分割成若干不同?br /> 分区Q不能放入内存的部分把该分区写入磁盘的临时D,此时要有较大的时段从而尽?br /> 提高I/O 的性能?br /> 也可以用USE_HASH(table_name1 table_name2)提示来强制用散列连接。如果用散 列连接HASH_AREA_SIZE 初始化参数必够的大,如果?iQOracle使用SQL工作?br /> 自动理Q设|WORKAREA_SIZE_POLICY 为AUTOQ然后调整PGA_AGGREGATE_TARGET 卛_?br /> 排序合ƈq接 通常情况下散列连接的效果都比排序合ƈq接要好Q然而如果行源已l被排过序,在执 行排序合q连接时不需要再排序了,q时排序合ƈq接的性能会优于散列连接。可以?br /> USE_MERGE(table_name1 table_name2)来强制用排序合q连?/div> Nested loop join:
步骤Q确定一个驱动表(outer table)Q另一个表为inner tableQ驱动表中的每一行与inner表中的相应记录JOIN。类g个嵌套的循环。适用于驱动表的记录集比较(<10000Q而且inner表需要有有效的访问方法(IndexQ。需要注意的是:JOIN的顺序很重要Q驱动表的记录集一定要,q回l果集的响应旉是最快的?br /> cost = outer access cost + (inner access cost * outer cardinality) | 2 | NESTED LOOPS | | 3 | 141 | 7 (15)| | 3 | TABLE ACCESS FULL | EMPLOYEES | 3 | 60 | 4 (25)| | 4 | TABLE ACCESS BY INDEX ROWID| JOBS | 19 | 513 | 2 (50)| | 5 | INDEX UNIQUE SCAN | JOB_ID_PK | 1 | | | EMPLOYEES为outer table, JOBS为inner table. Hash join 步骤Q将两个表中较小的一个在内存中构造一个HASH表(对JOIN KEYQ,扫描另一个表Q同样对JOIN KEYq行HASH后探是否可以JOIN。适用于记录集比较大的情况。需要注意的是:如果HASH表太大,无法一ơ构造在内存中,则分成若q个partitionQ写入磁盘的temporary segmentQ则会多一个写的代P会降低效率?br /> cost = (outer access cost * # of hash partitions) + inner access cost -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 665 | 13300 | 8 (25)| | 1 | HASH JOIN | | 665 | 13300 | 8 (25)| | 2 | TABLE ACCESS FULL | ORDERS | 105 | 840 | 4 (25)| | 3 | TABLE ACCESS FULL | ORDER_ITEMS | 665 | 7980 | 4 (25)| -------------------------------------------------------------------------- ORDERS为HASH TABLEQORDER_ITEMS扫描 Sort merge join 步骤Q将两个表排序,然后两个表合ƈ。通常情况下,只有在以下情况发生时Q才会用此UJOIN方式Q?br /> 1.RBO模式 2.不等价关?>,<,>=,<=,<>) 3.HASH_JOIN_ENABLED=false 4.数据源已排序 cost = (outer access cost * # of hash partitions) + inner access cost 转蝲biti的一D话:
举例Q表q接q回一条记? 存在两个表,一? 10条记? Q一?000万条记录 ?表都存在q接字段索引Q若以小表ؓ驱动表,? 代hQ? 10* (通过索引在大表查询一条记录的代h) 若以大表为驱动表Q? 1000? * (通过索引在小表中查询一条记录的代h) 通过索引获取一条记录,10rows的表Q代价通常? 3 blocks 索引2块,表一? 而如果是1000万的表,索引可能辑ֈ4块表一? q样一来参考上面的计算Q你说哪个更好?很显Ӟ 表查询参? SQL> create table test as select * from all_objects where rownum < 11; Table created. SQL> create index test_index on test(object_id); Index created. SQL> select object_id from test; OBJECT_ID ---------- 18159 7781 4841 19891 22549 17099 17712 4287 10107 19135 10 rows selected. Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 TABLE ACCESS (FULL) OF 'TEST' Statistics ---------------------------------------------------------- 0 recursive calls 12 db block gets 6 consistent gets 0 physical reads 0 redo size 736 bytes sent via SQL*Net to client 425 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 10 rows processed SQL> select * from test where object_id = 4287; OWNER OBJECT_NAME ------------------------------ ------------------------------ SUBOBJECT_NAME OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE ------------------------------ ---------- -------------- ------------------ CREATED LAST_DDL_ TIMESTAMP STATUS T G S --------- --------- ------------------- ------- - - - SYS /1033c8a_SqlTypeWithMethods 4287 JAVA CLASS 14-NOV-00 03-JUL-03 2003-07-03:11:18:19 INVALID N N N Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TEST' 2 1 INDEX (RANGE SCAN) OF 'TEST_INDEX' (NON-UNIQUE) Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 3 consistent gets 0 physical reads 0 redo size 1157 bytes sent via SQL*Net to client 425 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed |
何谓“持久?#8221;
持久层(Persistence LayerQ,即专注于实现数据持久化应用领域的某个特定pȝ的一个逻辑层面Q将数据使用者和数据实体相关联?/p>
何谓“对象数据映射QORMQ?#8221;
ORM-Object/Relational MapperQ即“对象-关系型数据映组?#8221;。对于O/RQ即 ObjectQ对象)?RelationalQ关pd数据Q,表示必须同时使用面向对象和关pd数据q行开发?/p>
备注Q徏模领域中?ORM ?Object/Role ModelingQ对象角色徏模)。另外这里是“O/R Mapper”而非“O/R Mapping”。相ҎԌO/R Mapping 描述的是一U设计思想或者实现机Ӟ?O/R Mapper指以O/R原理设计的持久化框架QFrameworkQ,包括 O/R机制q有 SQL自生成,事务处理QCache理{?/p>
除了 ORM 技术,q有以下几种持久化技?/p>
d域对象模?br /> 它是在实C装了关pL据模型和数据讉Kl节的一UŞ式。在 J2EE 架构中,EJB lg分ؓ会话 EJB 和实?EJB。会?EJB 通常实现业务逻辑Q而实?EJB 表示业务实体。实?EJB 又分ZU:?EJB 本n理持久化,?BMPQBean-Managed PersistenceQ;?EJB 容器理持久化,?CMPQContainer-Managed PersistenceQ。BM P是d域对象模式的一个例子,BMP 表示由实?EJB 自n理数据讉Kl节?br /> d域对象本w位于业务逻辑层,因此采用d域对象模式时Q整个应用仍然是三层应用l构Qƈ没有从业务逻辑层分d独立的持久化层?/p>
JDO 模式
Java Data ObjectsQJDOQ是 SUN 公司制定的描q对象持久化语义的标准API。严格的_JDO q不是对?关系映射接口Q因为它支持把对象持久化CQ意一U存储系l中Q包?关系数据库、面向对象的数据库、基?XML 的数据库Q以及其他专有存储系l。由于关pL据库是目前最行的存储系l,许多 JDO 的实现都包含了对?关系映射服务?/p>
CMP 模式
?J2EE 架构中,CMPQContainer-Managed PersistenceQ表C由 EJB 容器来管理实?EJB 的持久化QEJB 容器装了对?关系的映及数据讉Kl节。CMP ?ORM 的相g处在于,两者都提供对象-关系映射服务Q都把对象持久化的Q务从业务逻辑中分d来。区别在?CMP 负责持久化实?EJB lgQ?ORM 负责持久?POJOQ它是普通的Z Java Bean 形式的实体域对象?/p>
一般把Z Java Bean 形式的实体域对象UCؓ POJOQPlain Old Java ObjectQ,意ؓ又普通又古老的 Java 对象的意思。随着各种 ORM 映射工具的日成熟和行QPOJO有重现光彩,它和Z CMP 的实?EJB 相比Q即单又h很高的可UL性,因此联合使用 ORM 映射工具?POJOQ已l成ZU越来越受欢q的且用来取?CMP 的持久化Ҏ。POJO 的缺点就是无法做q程调用Q不支持分布式计?/p>
Z么要做持久化和ORM设计
在目前的企业应用pȝ设计中,MVCQ即 ModelQ模型)- ViewQ视图)- ControlQ控ӞZ要的pȝ架构模式。MVC 中的 Model 包含了复杂的业务逻辑和数据逻辑Q以及数据存取机Ӟ?JDBC的连接、SQL生成和Statement创徏、还有ResultSetl果集的d{){。将q些复杂的业务逻辑和数据逻辑分离Q以系l的紧耦合关系转化为松耦合关系Q即解耦合Q,是降低系l耦合度迫切要做的Q也是持久化要做的工作。MVC 模式实现了架构上表现层Q即ViewQ和数据处理层(即ModelQ分ȝ解耦合Q而持久化的设计则实现了数据处理层内部的业务逻辑和数据逻辑分离的解耦合。?ORM 作ؓ持久化设计中的最重要也最复杂的技术,也是目前业界热点技术?/p>
单来_按通常的系l设计,使用 JDBC 操作数据库,业务处理逻辑和数据存取逻辑是杂在一L?br />
一般基本都是如下几个步骤:
1、徏立数据库q接Q获?Connection 对象?br />
2、根据用L输入l装查询 SQL 语句?br />
3、根?SQL 语句建立 Statement 对象 或?PreparedStatement 对象?br />
4、用 Connection 对象执行 SQL语句Q获得结果集 ResultSet 对象?br />
5、然后一条一条读取结果集 ResultSet 对象中的数据?br />
6、根据读取到的数据,按特定的业务逻辑q行计算?br />
7、根据计得到的l果再组装更?SQL 语句?br />
8、再使用 Connection 对象执行更新 SQL 语句Q以更新数据库中的数据?br />
7、最后依ơ关闭各?Statement 对象?Connection 对象?/p>
׃可看Z码逻辑非常复杂Q这q不包括某条语句执行p|的处理逻辑。其中的业务处理逻辑和数据存取逻辑完全h在一块。而一个完整的pȝ要包含成千上万个q样重复的而又h的处理过E,假如要对其中某些业务逻辑或者一些相兌的业务流E做修改Q要改动的代码量不可想象。另一斚wQ假如要换数据库产品或者运行环境也可能是个不可能完成的d。而用Lq行环境和要求却千差万别Q我们不可能为每一个用h一U运行环境设计一套一Lpȝ?br /> 所以就要将一L处理代码即业务逻辑和可能不一L处理x据存取逻辑分离开来,另一斚wQ关pd数据库中的数据基本都是以一行行的数据进行存取的Q而程序运行却是一个个对象q行处理Q而目前大部分数据库驱动技术(如ADO.NET、JDBC、ODBC{等Q均是以行集的结果集一条条q行处理的。所以ؓ解决q一困难Q就出现 ORM q一个对象和数据之间映射技术?/p>
举例来说Q比如要完成一个购物打折促销的程序,?ORM 思想如下实玎ͼ引自《深入浅出Hibernate》)Q?br />
业务逻辑如下Q?br />
public Double calcAmount(String customerid, double amount)
{
// Ҏ客户ID获得客户记录
Customer customer = CustomerManager.getCustomer(custmerid);
// Ҏ客户{获得打折规则
Promotion promotion = PromotionManager.getPromotion(customer.getLevel());
// 累积客户L贚wQƈ保存累计l果
customer.setSumAmount(customer.getSumAmount().add(amount);
CustomerManager.save(customer);
// q回打折后的金额
return amount.multiply(protomtion.getRatio());
}
q样代码非常清CQ而且与数据存取逻辑完全分离。设计业务逻辑代码的时候完全不需要考虑数据库JDBC的那些千一律的操作Q而将它交l?CustomerManager ?PromotionManager 两个cd完成。这是一个简单的 ORM 设计Q实际的 ORM 实现框架比这个要复杂的多?/p>
目前有哪些流行的 ORM 产品
目前众多厂商和开源社区都提供了持久层框架的实玎ͼ常见的有
Apache OJB Q?a >http://db.apache.org/ojb/Q?br />
Cayenne Q?a >http://objectstyle.org/cayenne/Q?br />
Jaxor Q?a >http://jaxor.sourceforge.netQ?br />
Hibernate Q?a >http://www.hibernate.orgQ?br />
iBatis Q?a >http://www.ibatis.comQ?br />
jRelationalFramework Q?a >http://ijf.sourceforge.netQ?br />
mirage Q?a >http://itor.cq2.org/en/oss/mirage/toonQ?br />
SMYLE Q?a >http://www.drjava.de/smyleQ?br />
TopLink Q?a >http://otn.oracle.com/products/ias/toplink/index.htmlQ?br />
其中 TopLink ?Oracle 的商业品,其他均ؓ开源项目?/p>
其中 Hibernate 的轻量 ORM 模型逐步立了在 Java ORM 架构中领导地位,甚至取代复杂而又J琐?EJB 模型而成Z实上?Java ORM 工业标准。而且其中的许多设计均?J2EE 标准l织吸纳而成为最?EJB 3.0 规范的标准,q也是开源项目媄响工业领域标准的有力见证?/p>
http://www.tkk7.com/fyz210/archive/2007/05/22/119098.html
对象关系映射Q?/span>Q简U?/span>Q,是随着面向对象的Y件开发方法发展而生的面向对象的开发方法是当今企业U应用开发环境中的主开发方法,关系数据库是企业U应用环境中怹存放数据的主数据存储系l?/span>面向对象是从软g工程基本原则(如耦合、聚合、封?的基上发展v来的Q而关pL据库则是从数学理论发展而来的,两套理论存在显著的区别。ؓ了解册个不匚w的现?对象关系映射技术应q而生?/span>
让我们从O/R开始。字母Oh?对象"(Object),而R则来自于"关系"(Relational)。几乎所有的E序里面Q都存在对象和关pL据库。在业务逻辑层和用户界面层中Q我们是面向对象的。当对象信息发生变化的时候,我们需要把对象的信息保存在关系数据库中?/span>
当你开发一个应用程序的时?不用O/R Mapping),你可能会写不数据访问层的代码,用来从数据库保存Q删除,d对象信息Q等{。你在DAL中写了很多的Ҏ来读取对象数据,改变状态对象等{Q务。而这些代码写hL重复的?/span>
u CRUDAPIu APIu mapping metadatau ORMdirty checking, lazy association fetchingORM,,,.
: