??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲热线99精品视频,亚洲中文无码线在线观看,久久精品国产亚洲av成人http://m.tkk7.com/weidagang2046/category/1067.html物格而后知致zh-cnFri, 02 Mar 2007 07:33:11 GMTFri, 02 Mar 2007 07:33:11 GMT60在应用中加入全文(g)索功能——基于Java的全文烦(ch)引引擎Lucene?/title><link>http://m.tkk7.com/weidagang2046/articles/87684.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Thu, 14 Dec 2006 05:05:00 GMT</pubDate><guid>http://m.tkk7.com/weidagang2046/articles/87684.html</guid><wfw:comment>http://m.tkk7.com/weidagang2046/comments/87684.html</wfw:comment><comments>http://m.tkk7.com/weidagang2046/articles/87684.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/weidagang2046/comments/commentRss/87684.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/weidagang2046/services/trackbacks/87684.html</trackback:ping><description><![CDATA[ <p>作者:(x) 车东 Email: chedongATbigfoot.com/chedongATchedong.com</p> <p>写于Q?002/08 最后更斎ͼ(x) <script language="Javascript" src="http://www.chedong.com/referer.js"></script> 11/29/2006 17:23:30<br /><a >Feed Back >></a> (tng)(<a >Read this before you ask question</a>)<a ><br /><img alt="Creative Commons License" src="http://www.creativecommons.cn/images/public/somerights.gif" border="0" /></a><q告></p> <p>版权声明Q可以Q意{载,转蝲时请务必以超链接形式标明文章原始出处和作者信息及(qing)本声?br /><a >http://www.chedong.com/tech/lucene.html</a></p> <p>关键词:(x)Lucene java full-text search engine (tng)Chinese (tng)word segment</p> <p> <span style="FONT-WEIGHT: bold"> </span>内容摘要Q?/p> <p>Lucene是一个基于Java的全文烦(ch)引工具包?/p> <ol> <li> <a >ZJava的全文烦(ch)引引擎Lucene介:(x)关于作者和Lucene的历?/a> </li> <li> <a >全文(g)索的实现QLuene全文索引和数据库索引的比?/a> </li> <li> <a >中文切分词机制简介:(x)Z词库和自动切分词法的比?/a> </li> <li> <a >具体的安装和使用介:(x)pȝl构介绍和演C?/a> </li> <li> <a >Hacking LuceneQ简化的查询分析器,删除的实玎ͼ定制的排序,应用接口的扩?/a> </li> <li> <a >从Lucene我们q可以学C?/a> </li> </ol> <p> <a name="intro"> <b>ZJava的全文烦(ch)?(g)索引擎——Lucene</b> </a> </p> <p>Lucene不是一个完整的全文索引应用Q而是是一个用Java写的全文索引引擎工具包,它可以方便的嵌入到各U应用中实现针对应用的全文烦(ch)?(g)索功能?/p> <p>Lucene的作者:(x)Lucene的A(ch)献?a >Doug Cutting</a>是一位资深全文烦(ch)?(g)索专Ӟ曄是V-Twin搜烦(ch)引擎(Apple的Copland操作pȝ的成׃一)的主要开发者,后在Excite担Q高pȝ架构设计师,目前从事于一些INTERNET底层架构的研I。他贡献出的Lucene的目标是为各U中型应用E序加入全文(g)索功能?/p> <p>Lucene的发展历E:(x)早先发布在作者自q<a >www.lucene.com</a>Q后来发布在<a >SourceForge</a>Q?001q年底成为APACHE基金?x)jakarta的一个子目Q?a >http://jakarta.apache.org/lucene/</a></p> <p>已经有很多Java目都用了(jin)Lucene作ؓ(f)其后台的全文索引引擎Q比较著名的有:(x)</p> <ul> <li> <a >J</a> <a >ive</a>QWEB论坛pȝQ? </li> <li> <a >Eyebrows</a>Q邮件列表HTML归档/览/查询pȝQ本文的主要参考文档?a >TheLucene search engine: Powerful, flexible, and free</a>”作者就是EyeBrowspȝ的主要开发者之一Q而EyeBrows已经成ؓ(f)目前APACHE目的主要邮件列表归档系l? </li> <li> <a >Cocoon</a>:ZXML的web发布框架Q全文检索部分用了(jin)Lucene </li> <li> <p align="left"> <a >Eclipse</a>:ZJava的开攑ּ发^収ͼ帮助部分的全文烦(ch)引用了(jin)Lucene</p> </li> </ul> <p>对于中文用户来说Q最兛_(j)的问题是其是否支持中文的全文(g)索。但通过后面对于Lucene的结构的介绍Q你?x)?jin)解到׃Lucene良好架构设计Q对中文的支持只需对其语言词法分析接口q行扩展p实现对中文检索的支持?/p> <p> <b> <a name="compare">全文(g)索的实现机制</a> </b> </p> <p>Lucene的API接口设计的比较通用Q输入输出结构都很像数据库的?=>记录==>字段Q所以很多传l的应用的文件、数据库{都可以比较方便的映到Lucene的存储结?接口中。M上看Q可以先?b>Lucene当成一个支持全文烦(ch)引的数据库系l?/b>?/p> <p>比较一下Lucene和数据库Q?/p> <table width="100%" border="1"> <tbody> <tr> <td align="middle" width="50%">Lucene</td> <td align="middle" width="50%">数据?/td> </tr> <tr> <td width="50%"> <pre>索引数据源:(x)doc(field1,field2...) doc(field1,field2...)<br /> \ indexer /<br /> _____________<br /> | Lucene Index|<br /> --------------<br /> / searcher \<br /> l果输出QHits(doc(field1,field2) doc(field1...))</pre> </td> <td width="50%"> <pre> 索引数据源:(x)record(field1,field2...) record(field1..)<br /> \ SQL: insert/<br /> _____________<br /> | DB Index |<br /> -------------<br /> / SQL: select \<br />l果输出Qresults(record(field1,field2..) record(field1...))</pre> </td> </tr> <tr> <td width="50%">DocumentQ一个需要进行烦(ch)引的“单元?br />一个Document由多个字D늻?/td> <td width="50%">RecordQ记录,包含多个字段</td> </tr> <tr> <td width="50%">FieldQ字D?/td> <td width="50%">FieldQ字D?/td> </tr> <tr> <td width="50%">HitsQ查询结果集Q由匚w的Documentl成</td> <td width="50%">RecordSetQ查询结果集Q由多个Recordl成</td> </tr> </tbody> </table> <p> <b>全文(g)??like "%keyword%"</b> </p> <p>通常比较厚的书籍后面常常附关键词索引表(比如Q北京:(x)12, 34,上vQ?,77……)(j)Q它能够帮助读者比较快地找到相兛_容的늠。而数据库索引能够大大提高查询的速度原理也是一P惛_一下通过书后面的索引查找的速度要比一一地d定w多少倍……而烦(ch)引之所以效率高Q另外一个原因是它是排好序的?b>对于(g)索系l来说核?j)是一个排序问?/b>?/p> <p align="left">׃数据库烦(ch)引不是ؓ(f)全文索引设计的,因此Q?b>使用like "%keyword%"Ӟ数据库烦(ch)引是不v作用?/b>Q在使用like查询Ӟ搜烦(ch)q程又变成类g一页M的遍历过E了(jin)Q所以对于含有模p查询的数据库服务来_(d)LIKEҎ(gu)能的危x极大的。如果是需要对多个关键词进行模p匹配:(x)like"%keyword1%" and like "%keyword2%" ...其效率也可惌知?jin)?/p> <p>所以徏立一个高效检索系l的关键是徏立一个类gU技索引一L(fng)反向索引机制Q将数据源(比如多篇文章Q排序顺序存储的同时Q有另外一个排好序的关键词列表Q用于存储关键词==>文章映射关系Q利用这L(fng)映射关系索引Q[关键?=>出现关键词的文章~号Q出现次敎ͼ甚至包括位置Qv始偏U量Q结束偏U量Q,出现频率]Q检索过E就是把<b>模糊查询变成多个可以利用索引的精查询的逻辑l合的过E?/b>。从而大大提高了(jin)多关键词查询的效率,所以,全文(g)索问题归l到最后是一个排序问题?/p> <p>由此可以看出模糊查询相对数据库的_查询是一个非怸定的问题,q也是大部分数据库对全文(g)索支持有限的原因。Lucene最核心(j)的特征是通过Ҏ(gu)的烦(ch)引结构实C(jin)传统数据库不擅长的全文烦(ch)引机Ӟq提供了(jin)扩展接口Q以方便针对不同应用的定制?/p> <p>可以通过一下表格对比一下数据库的模p查询:(x)</p> <table height="283" width="100%" border="1"> <tbody> <tr> <td align="middle" width="9%" height="16"> </td> <td align="middle" width="47%" height="16">Lucene全文索引引擎</td> <td align="middle" width="40%" height="16">数据?/td> </tr> <tr> <td width="9%" height="48">索引</td> <td width="47%" height="48">数据源中的数据都通过全文索引一一建立反向索引</td> <td width="40%" height="48">对于LIKE查询来说Q数据传l的索引是根本用不上的。数据需要逐个便利记录q行GREP式的模糊匚wQ比有烦(ch)引的搜烦(ch)速度要有多个数量U的下降?/td> </tr> <tr> <td width="9%" height="49">匚w效果</td> <td width="47%" height="49">通过词元(term)q行匚wQ通过语言分析接口的实玎ͼ可以实现对中文等非英语的支持?/td> <td width="40%" height="49">使用Qlike "%net%" ?x)把netherlands也匹配出来,<br />多个关键词的模糊匚wQ用like "%com%net%"Q就不能匚w词序颠倒的xxx.net..xxx.com</td> </tr> <tr> <td width="9%" height="32">匚w?/td> <td width="47%" height="32">有匹配度法Q将匚wE度Q相似度Q比较高的结果排在前面?/td> <td width="40%" height="32">没有匚wE度的控Ӟ(x)比如有记录中net出现5词和出现1ơ的Q结果是一L(fng)?/td> </tr> <tr> <td width="9%" height="32">l果输出</td> <td width="47%" height="32">通过特别的算法,最匚w度最高的?00条结果输出,l果集是~冲式的批量读取的?/td> <td width="40%" height="32">q回所有的l果集,在匹配条目非常多的时候(比如上万条)(j)需要大量的内存存放q些临时l果集?/td> </tr> <tr> <td width="9%" height="32">可定制?/td> <td width="47%" height="32">通过不同的语a分析接口实现Q可以方便的定制出符合应用需要的索引规则Q包括对中文的支持)(j)</td> <td width="40%" height="32">没有接口或接口复杂,无法定制</td> </tr> <tr> <td width="9%" height="32">l论</td> <td width="47%" height="32">高负载的模糊查询应用Q需要负责的模糊查询的规则,索引的资料量比较?/td> <td width="40%" height="32">使用率低Q模p匹配规则简单或者需要模p查询的资料量少</td> </tr> </tbody> </table> <p> <span style="FONT-WEIGHT: bold">全文(g)索和数据库应用最大的不同在于Q让</span> <span style="FONT-WEIGHT: bold">最相关?/span> <span style="FONT-WEIGHT: bold">?00条结果满?8%以上用户的需?br /></span> <br />Lucene的创C处:(x)</p> <p>大部分的搜烦(ch)Q数据库Q引擎都是用B?wi)结构来l护索引Q烦(ch)引的更新?x)导致大量的IO操作QLucene在实CQ对此稍微有所改进Q不是维护一个烦(ch)引文Ӟ而是在扩展烦(ch)引的时候不断创建新的烦(ch)引文Ӟ然后定期的把q些新的烦(ch)引文件合q到原先的大索引中(针对不同的更新策略,Ҏ(gu)的大可以调_(d)(j)Q这样在不媄(jing)响检索的效率的前提下Q提高了(jin)索引的效率?/p> <p>Lucene和其他一些全文检索系l?应用的比较:(x)</p> <table width="100%" border="1"> <tbody> <tr> <td align="middle" width="18%"> </td> <td align="middle" width="45%">Lucene</td> <td align="middle" width="37%">其他开源全文检索系l?/td> </tr> <tr> <td width="18%">增量索引和批量烦(ch)?/td> <td width="45%">可以q行增量的烦(ch)?Append)Q可以对于大量数据进行批量烦(ch)引,q且接口设计用于优化扚w索引和小扚w的增量烦(ch)引?/td> <td width="37%">很多pȝ只支持批量的索引Q有时数据源有一点增加也需要重建烦(ch)引?/td> </tr> <tr> <td width="18%">数据?/td> <td width="45%">Lucene没有定义具体的数据源Q而是一个文档的l构Q因此可以非常灵zȝ适应各种应用Q只要前端有合适的转换器把数据源{换成相应l构Q,</td> <td width="37%">很多pȝ只针对网,~Z其他格式文档的灵zL?/td> </tr> <tr> <td width="18%">索引内容抓取</td> <td width="45%">Lucene的文档是由多个字D늻成的Q甚臛_以控刉些字D需要进行烦(ch)引,那些字段不需要烦(ch)引,q一步烦(ch)引的字段也分为需要分词和不需要分词的cdQ?br /> (tng) (tng) 需要进行分词的索引Q比如:(x)标题Q文章内容字D?br /> (tng) (tng) 不需要进行分词的索引Q比如:(x)作?日期字段</td> <td width="37%">~Z通用性,往往文档整个烦(ch)引了(jin)</td> </tr> <tr> <td width="18%">语言分析</td> <td width="45%">通过语言分析器的不同扩展实现Q?br />可以qo(h)掉不需要的词:(x)an the of {,<br />西文语法分析Q将jumps jumped jumper都归l成jumpq行索引/(g)?br />非英文支持:(x)对亚z语aQ阿拉伯语言的烦(ch)引支?/td> <td width="37%">~Z通用接口实现</td> </tr> <tr> <td width="18%">查询分析</td> <td width="45%">通过查询分析接口的实玎ͼ可以定制自己的查询语法规则:(x)<br />比如Q?多个关键词之间的 + - and or关系{?/td> <td width="37%"> </td> </tr> <tr> <td width="18%">q发讉K</td> <td width="45%">能够支持多用L(fng)使用</td> <td width="37%"> </td> </tr> </tbody> </table> <p> </p> <p> <b> <a name="segment">关于亚洲语言的的切分词问?Word Segment)</a> </b> </p> <p>对于中文来说Q全文烦(ch)引首先还要解决一个语a分析的问题,对于英文来说Q语句中单词之间是天焉过I格分开的,但亚z语a的中日韩文语句中的字是一个字挨一个,所有,首先要把语句中按“词”进行烦(ch)引的话,q个词如何切分出来就是一个很大的问题?/p> <p>首先Q肯定不能用单个字符?si-gram)为烦(ch)引单元,否则查“上”时Q不能让含有“v上”也匚w?/p> <p>但一句话Q“北京天安门”,计算机如何按照中文的语言?fn)惯q行切分呢?<br />“北?天安门?q是“北 ?天安门”?让计机能够按照语言?fn)惯q行切分Q往往需要机器有一个比较丰富的词库才能够比较准的识别?gu)句中的单词?/p> <p>另外一个解决的办法是采用自动切分算法:(x)单词按?元语?bigram)方式切分出来Q比如:(x)<br />"北京天安? ==> "北京 京天 天安 安门"?/p> <p>q样Q在查询的时候,无论是查?北京" q是查询"天安?Q将查询词组按同L(fng)规则q行切分Q?北京"Q?天安安门"Q多个关键词之间按与"and"的关pȝ合,同样能够正确地映到相应的烦(ch)引中。这U方式对于其他亚z语aQ韩文,日文都是通用的?/p> <p>Z自动切分的最大优Ҏ(gu)没有词表l护成本Q实现简单,~点是烦(ch)引效率低Q但对于中小型应用来_(d)Z2元语法的切分q是够用的。基?元切分后的烦(ch)引一般大和源文件差不多Q而对于英文,索引文g一般只有原文g?0%-40%不同Q?/p> <table height="68" width="100%" border="1"> <tbody> <tr> <td align="middle" width="11%" height="18"> <br /> </td> <td align="middle" width="39%" height="18">自动切分</td> <td align="middle" width="50%" height="18">词表切分</td> </tr> <tr> <td width="11%" height="16">实现</td> <td width="39%" height="16">实现非常?/td> <td width="50%" height="16">实现复杂</td> </tr> <tr> <td width="11%" height="16">查询</td> <td width="39%" height="16">增加?jin)查询分析的复杂E度Q?/td> <td width="50%" height="16">适于实现比较复杂的查询语法规?/td> </tr> <tr> <td width="11%" height="16">存储效率</td> <td width="39%" height="16">索引冗余大,索引几乎和原文一样大</td> <td width="50%" height="16">索引效率高,为原文大的30Q左?/td> </tr> <tr> <td width="11%" height="16">l护成本</td> <td width="39%" height="16">无词表维护成?/td> <td width="50%" height="16">词表l护成本非常高:(x)中日韩等语言需要分别维护?br />q需要包括词频统计等内容</td> </tr> <tr> <td width="11%" height="16">适用领域</td> <td width="39%" height="16">嵌入式系l:(x)q行环境资源有限<br />分布式系l:(x)无词表同步问?br />多语a环境Q无词表l护成本</td> <td width="50%" height="16">Ҏ(gu)询和存储效率要求高的专业搜烦(ch)引擎<br /></td> </tr> </tbody> </table> <p>目前比较大的搜烦(ch)引擎的语a分析法一般是Z以上2个机制的l合。关于中文的语言分析法Q大家可以在Google查关键词"wordsegment search"能找到更多相关的资料?/p> <p> <a name="demo"> <b>安装和?/b> </a> </p> <p>下蝲Q?a >http://jakarta.apache.org/lucene/</a></p> <p>注意QLucene中的一些比较复杂的词法分析是用JavaCC生成的(JavaCCQJavaCompilerCompilerQ纯Java的词法分析生成器Q,所以如果从源代码编译或需要修改其中的QueryParser、定制自q词法分析器,q需要从<a >https://javacc.dev.java.net/</a>下蝲javacc?/p> <p>lucene的组成结构:(x)对于外部应用来说索引模块(index)和检索模?search)是主要的外部应用入口</p> <table width="100%" border="1"> <tbody> <tr> <td width="27%">org.apache.Lucene.search/</td> <td width="73%">搜烦(ch)入口</td> </tr> <tr> <td width="27%">org.apache.Lucene.index/</td> <td width="73%">索引入口</td> </tr> <tr> <td width="27%">org.apache.Lucene.analysis/</td> <td width="73%">语言分析?/td> </tr> <tr> <td width="27%">org.apache.Lucene.queryParser/</td> <td width="73%">查询分析?/td> </tr> <tr> <td width="27%">org.apache.Lucene.document/</td> <td width="73%">存储l构</td> </tr> <tr> <td width="27%">org.apache.Lucene.store/ (tng)</td> <td width="73%">底层IO/存储l构</td> </tr> <tr> <td width="27%">org.apache.Lucene.util/</td> <td width="73%">一些公用的数据l构</td> </tr> </tbody> </table> <p>单的例子演示一下Lucene的用方法:(x)</p>索引q程Q从命o(h)行读取文件名Q多个)(j)Q将文g分\?path字段)和内?body字段)2个字D进行存储,q对内容q行全文索引Q烦(ch)引的单位是Document对象Q每个Document对象包含多个字段Field对象Q针对不同的字段属性和数据输出的需求,对字D还可以选择不同的烦(ch)?存储字段规则Q列表如下:(x) <table border="1"><tbody><tr><th>Ҏ(gu)</th><th>切词</th><th>索引</th><th>存储</th><th>用?/th></tr><tr><td>Field.Text(String name, String value)</td><td>Yes</td><td>Yes</td><td>Yes</td><td valign="top">切分词烦(ch)引ƈ存储Q比如:(x)标题Q内容字D?/td></tr><tr><td>Field.Text(String name, Reader value)</td><td>Yes</td><td>Yes</td><td>No</td><td valign="top">切分词烦(ch)引不存储Q比如:(x)META信息Q?br />不用于返回显C,但需要进行检索内?/td></tr><tr><td>Field.Keyword(String name, String value)</td><td>No</td><td>Yes</td><td>Yes</td><td valign="top">不切分烦(ch)引ƈ存储Q比如:(x)日期字段</td></tr><tr><td>Field.UnIndexed(String name, String value)</td><td>No</td><td>No</td><td>Yes</td><td valign="top">不烦(ch)引,只存储,比如Q文件\?/td></tr><tr><td>Field.UnStored(String name, String value)</td><td>Yes</td><td>Yes</td><td>No</td><td valign="top">只全文烦(ch)引,不存?/td></tr></tbody></table><pre>public class IndexFiles { <br /> //使用Ҏ(gu)Q? IndexFiles [索引输出目录] [索引的文件列表] ... <br /> public static void main(String[] args) throws Exception {<br /> String indexPath = args[0];<br /> IndexWriter writer;<br /> //用指定的语言分析器构造一个新的写索引器(W?个参数表C是否ؓ(f)q加索引Q?br /> writer = new IndexWriter(indexPath, new SimpleAnalyzer(), false);<br /><br /> for (int i=1; i<args.length; i++) {<br /> System.out.println("Indexing file " + args[i]);<br /> InputStream is = new FileInputStream(args[i]);<br /><br /> //构造包?个字DField的Document对象<br /> //一个是路径path字段Q不索引Q只存储<br /> //一个是内容body字段Q进行全文烦(ch)引,q存?br /> Document doc = new Document();<br /> doc.add(Field.UnIndexed("path", args[i]));<br /> doc.add(Field.Text("body", (Reader) new InputStreamReader(is)));<br /> //文档写入烦(ch)?br /> writer.addDocument(doc);<br /> is.close();<br /> };<br /> //关闭写烦(ch)引器<br /> writer.close();<br /> }<br />}<br /> </pre><p>索引q程中可以看刎ͼ(x)</p><ul><li>语言分析器提供了(jin)抽象的接口,因此语言分析(Analyser)是可以定制的Q虽然lucene~省提供?个比较通用的分析器SimpleAnalyser和StandardAnalyserQ这2个分析器~省都不支持中文Q所以要加入对中文语a的切分规则,需要修改这2个分析器? </li><li>Luceneq没有规定数据源的格式,而只提供?jin)一个通用的结构(Document对象Q来接受索引的输入,因此输入的数据源可以是:(x)数据库,W(xu)ORD文档QPDF文档QHTML文档……只要能够设计相应的解析转换器将数据源构造成成Docuement对象卛_q行索引? </li><li>对于大批量的数据索引Q还可以通过调整IndexerWrite的文件合q率属性(mergeFactorQ来提高扚w索引的效率?</li></ul><p>(g)索过E和l果昄Q?/p><p>搜烦(ch)l果q回的是Hits对象Q可以通过它再讉KDocument==>Field中的内容?/p><p>假设Ҏ(gu)body字段q行全文(g)索,可以查询结果的path字段和相应查询的匚w?score)打印出来Q?/p><pre>public class Search { <br /> public static void main(String[] args) throws Exception {<br /> String indexPath = args[0], queryString = args[1];<br /> //指向索引目录的搜索器<br /> Searcher searcher = new IndexSearcher(indexPath);<br /> //查询解析器:(x)使用和烦(ch)引同L(fng)语言分析?br /> Query query = QueryParser.parse(queryString, "body", <br /> new SimpleAnalyzer());<br /> //搜烦(ch)l果使用Hits存储<br /> Hits hits = searcher.search(query);<br /> //通过hits可以讉K到相应字D늚数据和查询的匚w?br /> for (int i=0; i<hits.length(); i++) {<br /> System.out.println(hits.doc(i).get("path") + "; Score: " + <br /> hits.score(i));<br /> };<br /> }<br />}</pre>在整个检索过E中Q语a分析器,查询分析器,甚至搜烦(ch)器(SearcherQ都是提供了(jin)抽象的接口,可以Ҏ(gu)需要进行定制? <p><b><a name="hacking">Hacking Lucene</a></b></p><p><b>化的查询分析?/b></p><p>个h感觉lucene成ؓ(f)JAKARTA目后,d?jin)太多的旉用于调试日趋复杂QueryParserQ而其中大部分是大多数用户q不很熟(zhn)的Q目前LUCENE支持的语法:(x)</p><p>Query ::= ( Clause )*<br />Clause ::= ["+", "-"] [<TERM> ":"] ( <TERM> | "(" Query ")")</p><p>中间的逻辑包括Qand or + - &&||{符P而且q有"短语查询"和针对西文的前缀/模糊查询{,个h感觉对于一般应用来_(d)q些功能有一些华而不实,其实能够实现目前cM于Google的查询语句分析功能其实对于大多数用户来说已经够了(jin)。所以,Lucene早期版本的QueryParser仍是比较好的选择?/p><p><b>d修改删除指定记录QDocumentQ?/b></p><p>Lucene提供?jin)?ch)引的扩展机制Q因此烦(ch)引的动态扩展应该是没有问题的,而指定记录的修改也似乎只能通过记录的删除,然后重新加入实现。如何删除指定的记录呢?删除的方法也很简单,只是需要在索引时根据数据源中的记录ID专门另徏索引Q然后利用IndexReader.delete(Termterm)Ҏ(gu)通过q个记录ID删除相应的Document?/p><p><b>Ҏ(gu)某个字段值的排序功能</b></p><p>lucene~省是按照自q相关度算法(scoreQ进行结果排序的Q但能够Ҏ(gu)其他字段q行l果排序是一个在LUCENE的开发邮件列表中l常提到的问题,很多原先Z数据库应用都需要除?jin)基于匹配度QscoreQ以外的排序功能。而从全文(g)索的原理我们可以?jin)解刎ͼM不基于烦(ch)引的搜烦(ch)q程效率都会(x)D效率非常的低Q如果基于其他字D늚排序需要在搜烦(ch)q程中访问存储字D,速度回大大降低,因此非常是不可取的?/p><p>但这里也有一个折中的解决Ҏ(gu)Q在搜烦(ch)q程中能够媄(jing)响排序结果的只有索引中已l存储的docID和scoreq?个参敎ͼ所以,Zscore以外的排序,其实可以通过数据源预先排好序,然后Ҏ(gu)docIDq行排序来实现。这样就避免?jin)在LUCENE搜烦(ch)l果外对l果再次q行排序和在搜烦(ch)q程中访问不在烦(ch)引中的某个字D倹{?/p><p>q里需要修改的是IndexSearcher中的HitCollectorq程Q?/p><pre>...<br /> scorer.score(new HitCollector() {<br /> private float minScore = 0.0f;<br /> public final void collect(int doc, float score) {<br /> if (score > 0.0f && // ignore zeroed buckets<br /> (bits==null || bits.get(doc))) { // skip docs not in bits<br /> totalHits[0]++;<br /> if (score >= minScore) {<br /> /* 原先QLucenedocID和相应的匚w度score例入l果命中列表中:(x)<br /> * hq.put(new ScoreDoc(doc, score)); // update hit queue<br /> * 如果用doc ?1/doc 代替 scoreQ就实现?jin)根据docID排或逆排<br /> * 假设数据源烦(ch)引时已经按照某个字段排好?jin)序Q而结果根据docID排序也就实现?br /> * 针对某个字段的排序,甚至可以实现更复杂的score和docID的拟合?br /> */<br /> hq.put(new ScoreDoc(doc, (float) 1/doc )); <br /> if (hq.size() > nDocs) { // if hit queue overfull<br /> hq.pop(); // remove lowest in hit queue<br /> minScore = ((ScoreDoc)hq.top()).score; // reset minScore<br /> }<br /> }<br /> }<br /> }<br /> }, reader.maxDoc());</pre><p><b>更通用的输入输出接?/b></p><p>虽然lucene没有定义一个确定的输入文档格式Q但来多的h惛_使用一个标准的中间格式作ؓ(f)Lucene的数据导入接口,然后其他数据Q比如PDF只需要通过解析器{换成标准的中间格式就可以q行数据索引?jin)。这个中间格式主要以XMLZQ类似实现已l不?Q?个:(x)</p><pre>数据? WORD PDF HTML DB other<br /> \ | | | /<br /> XML中间格式<br /> |<br /> Lucene INDEX</pre><p>目前q没有针对MSWord文档的解析器Q因为Word文档和基于ASCII的RTF文档不同Q需要用COM对象机制解析。这个是我在Google上查的相兌料:(x)<a >http://www.intrinsyc.com/products/enterprise_applications.asp</a><br />另外一个办法就是把Word文档转换成textQ?a >http://www.winfield.demon.nl/index.html</a><br /></p><p><br /><b>索引q程优化</b></p><p>索引一般分2U情况,一U是批量的索引扩展Q一U是大批量的索引重徏。在索引q程中,q不是每ơ新的DOC加入q去索引都重新进行一ơ烦(ch)引文件的写入操作Q文件I/O是一仉常消耗资源的事情Q?/p><p>Lucene先在内存中进行烦(ch)引操作,q根据一定的扚wq行文g的写入。这个批ơ的间隔大Q文件的写入ơ数少Q但占用内存?x)很多。反之占用内存少Q但文gIO操作频繁Q烦(ch)引速度?x)很慢。在IndexWriter中有一个MERGE_FACTOR参数可以帮助你在构造烦(ch)引器后根据应用环境的情况充分利用内存减少文g的操作。根据我的用经验:(x)~省Indexer是每20条记录烦(ch)引后写入一ơ,每将MERGE_FACTOR增加50倍,索引速度可以提高1倍左叟?br /></p><p><span style="FONT-WEIGHT: bold">搜烦(ch)q程优化<br /></span></p><p><span style="FONT-WEIGHT: bold"></span>lucene支持内存索引Q这L(fng)搜烦(ch)比基于文件的I/O有数量的速度提升?br /><a >http://www.onjava.com/lpt/a/3273</a><br />而尽可能减少IndexSearcher的创建和Ҏ(gu)索结果的前台的缓存也是必要的?br /><span style="FONT-WEIGHT: bold"></span></p><p><b></b></p><p>Lucene面向全文(g)索的优化在于首次索引(g)索后Qƈ不把所有的记录QDocumentQ具体内容读取出来,而v只将所有结果中匚w度最高的?00条结果(TopDocsQ的ID攑ֈl果集缓存中q返回,q里可以比较一下数据库(g)索:(x)如果是一?0,000条的数据库检索结果集Q数据库是一定要把所有记录内定w取得以后再开始返回给应用l果集的。所以即使检索匹配L很多QLucene的结果集占用的内存空间也不会(x)很多。对于一般的模糊(g)索应用是用不到这么多的结果的Q头100条已l可以满?0%以上的检索需求?br /></p><p>如果首批~存l果数用完后q要d更后面的l果时Searcher?x)再ơ检索ƈ生成一个上ơ的搜烦(ch)~存数大1倍的~存Qƈ再重新向后抓取。所以如果构造一个SearcherL1Q?20条结果,Searcher其实是进行了(jin)2ơ搜索过E:(x)?00条取完后Q缓存结果用完,Searcher重新(g)索再构造一?00条的l果~存Q依此类推,400条缓存,800条缓存。由于每ơSearcher对象消失后,q些~存也访问那不到?jin),你有可能惛_l果记录~存下来Q缓存数量保证?00以下以充分利用首ơ的l果~存Q不让Lucene费多次(g)索,而且可以分q行l果~存?br /></p><p>Lucene的另外一个特Ҏ(gu)在收集结果的q程中将匚w度低的结果自动过滤掉?jin)。这也是和数据库应用需要将搜烦(ch)的结果全部返回不同之处?/p><p><a >我的一些尝?/a>Q?/p><ul><li>支持中文的TokenizerQ这里有2个版本,一个是通过JavaCC生成的,对CJK部分按一个字W一个TOKEN索引Q另外一个是从SimpleTokenizer改写的,对英文支持数字和字母TOKENQ对中文按P代烦(ch)引? </li><li>ZXML数据源的索引器:(x)XMLIndexerQ因此所有数据源只要能够按照DTD转换成指定的XMLQ就可以用XMLIndxerq行索引?jin)? </li><li>Ҏ(gu)某个字段排序Q按记录索引序排序l果的搜索器QIndexOrderSearcherQ因此如果需要让搜烦(ch)l果Ҏ(gu)某个字段排序Q可以让数据源先按某个字D|好序Q比如:(x)PriceFieldQ,q样索引后,然后在利用这个按记录的ID序(g)索的搜烦(ch)器,l果是相当于是那个字段排序的结果了(jin)?</li></ul><p><a name="learn"><b>从Lucene学到更多</b></a></p><p>Luene的确是一个面对对象设计的典范</p><ul><li>所有的问题都通过一个额外抽象层来方便以后的扩展和重用:(x)你可以通过重新实现来达到自q目的Q而对其他模块而不需要; </li><li>单的应用入口Searcher, IndexerQƈ调用底层一pdlg协同的完成搜索Q务; </li><li>所有的对象的Q务都非常专一Q比如搜索过E:(x)QueryParser分析查询语句{换成一pd的精查询的l合(Query),通过底层的烦(ch)引读取结构IndexReaderq行索引的读取,q用相应的打分器l搜索结果进行打?排序{。所有的功能模块原子化程度非帔RQ因此可以通过重新实现而不需要修改其他模块。? </li><li>除了(jin)灉|的应用接口设计,Luceneq提供了(jin)一些适合大多数应用的语言分析器实玎ͼSimpleAnalyser,StandardAnalyserQ,q也是新用户能够很快上手的重要原因之一?</li></ul><p>q些优点都是非常值得在以后的开发中学习(fn)借鉴的。作Z个通用工具包,Lunece的确l予?jin)需要将全文(g)索功能嵌入到应用中的开发者很多的便利?/p><p>此外Q通过对Lucene的学?fn)和使用Q我也更深刻地理解了(jin)Z么很多数据库优化设计中要求,比如Q?/p><ul><li>可能对字段q行索引来提高查询速度Q但q多的烦(ch)引会(x)Ҏ(gu)据库表的更新操作变慢Q而对l果q多的排序条Ӟ实际上往往也是性能的杀手之一? </li><li>很多商业数据库对大批量的数据插入操作?x)提供一些优化参敎ͼq个作用和烦(ch)引器的merge_factor的作用是cM的, </li><li>20%/80%原则Q查的结果多q不{于质量好,其对于q回l果集很大,如何优化q头几十条结果的质量往往才是最重要的? </li><li>可能让应用从数据库中获得比较小的结果集Q因为即使对于大型数据库Q对l果集的随机讉K也是一个非常消耗资源的操作?br /></li></ul><p>参考资料:(x)</p><p>Apache: Lucene Project<br /><a >http://jakarta.apache.org/lucene/<br /></a>Lucene开?用户邮g列表归档<br /><a >Lucene-dev@jakarta.apache.org</a><br /><a >Lucene-user@jakarta.apache.org</a></p><p>The Lucene search engine: Powerful, flexible, and free<br /><a >http://www.javaworld.com/javaworld/jw-09-2000/jw-0915-Lucene_p.html</a></p><p>Lucene Tutorial<br /><a >http://www.darksleep.com/puff/lucene/lucene.html</a></p><p>Notes on distributed searching with Lucene<br /><a >http://home.clara.net/markharwood/lucene/</a></p><p>中文语言的切分词<br /><a >http://www.google.com/search?sourceid=navclient&hl=zh-CN&q=chinese+word+segment</a></p><p>搜烦(ch)引擎工具介绍<a ><br />http://searchtools.com/</a></p><p>Lucene作者Cutting的几论文和专利<br /><a >http://lucene.sourceforge.net/publications.html</a> (tng)</p><p>Lucene?NET实现QdotLucene<br /><a >http://sourceforge.net/projects/dotlucene/<br /></a></p><p>Lucene作者Cutting的另外一个项目:(x)ZJava的搜索引擎Nutch<br /><a >http://www.nutch.org/</a>  (tng) <a >http://sourceforge.net/projects/nutch/<br /></a></p><p>关于Z词表和N-Gram的切分词比较<br /><a >http://china.nikkeibp.co.jp/cgi-bin/china/news/int/int200302100112.html</a><br /><br />2005-01-08 <a >Cutting在Pisa大学做的关于Lucene的讲座:(x)非常详细的Lucene架构解说</a></p><p>特别感谢Q?br /><a >前网易CTO许良?Jack Xu)</a>l我的指|(x)是?zhn)我带入了(jin)搜索引擎这个行业?/p>原文出处Q?lt;a>http://www.chedong.com/tech/lucene.html</a><br /><br />from: <img src ="http://m.tkk7.com/weidagang2046/aggbug/87684.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/weidagang2046/" target="_blank">weidagang2046</a> 2006-12-14 13:05 <a href="http://m.tkk7.com/weidagang2046/articles/87684.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入出理解索引l构 http://m.tkk7.com/weidagang2046/articles/86464.htmlweidagang2046weidagang2046Fri, 08 Dec 2006 14:01:00 GMThttp://m.tkk7.com/weidagang2046/articles/86464.htmlhttp://m.tkk7.com/weidagang2046/comments/86464.htmlhttp://m.tkk7.com/weidagang2046/articles/86464.html#Feedback0http://m.tkk7.com/weidagang2046/comments/commentRss/86464.htmlhttp://m.tkk7.com/weidagang2046/services/trackbacks/86464.html阅读全文

weidagang2046 2006-12-08 22:01 发表评论
]]>
提高查询速度Ҏ(gu)ȝ http://m.tkk7.com/weidagang2046/articles/86461.htmlweidagang2046weidagang2046Fri, 08 Dec 2006 13:55:00 GMThttp://m.tkk7.com/weidagang2046/articles/86461.htmlhttp://m.tkk7.com/weidagang2046/comments/86461.htmlhttp://m.tkk7.com/weidagang2046/articles/86461.html#Feedback0http://m.tkk7.com/weidagang2046/comments/commentRss/86461.htmlhttp://m.tkk7.com/weidagang2046/services/trackbacks/86461.htmlq个帖子主要ȝ提高查询速度的方法,涉及(qing)到减连接数据库ơ数、徏立烦(ch)引、优化语句等斚w?/p>

关于索引Q推荐{载的q篇文章
http://blog.csdn.net/dutguoyi/archive/2006/01/10/575617.aspx

改善SQL语句的效?br />http://community.csdn.net/Expert/topic/5087/5087396.xml?temp=.345669
数据量很大怎样加快索检速度
http://community.csdn.net/Expert/topic/5058/5058320.xml?temp=.1229517
索引建立Ҏ(gu)的区?br />http://community.csdn.net/Expert/topic/5068/5068154.xml?temp=.3010218
频繁插入删除数据需要更新烦(ch)?br />http://community.csdn.net/Expert/topic/4937/4937910.xml?temp=.8428614
试?jin)一下sql server 2005 全文(g)?br />http://community.csdn.net/Expert/topic/4878/4878430.xml?temp=.6049311

其他关于效率的高频问?/p>

判断一个表的数据不在另一个表中最优秀Ҏ(gu)Q?br />http://community.csdn.net/Expert/topic/5038/5038742.xml?temp=.4704553
删除千万U表中重复记录的办法
http://community.csdn.net/Expert/topic/5089/5089261.xml?temp=.7907068

数据库数据查询变得不正常cd问题

大数据量Q稳定运行一D|候以后无法得到查询结果?br />http://community.csdn.net/Expert/topic/4810/4810464.xml?temp=9.014529E-02

from: http://m.tkk7.com/zqli/archive/2006/12/08/86391.html



weidagang2046 2006-12-08 21:55 发表评论
]]>
~写高性能Web应用E序?0个入门技?/title><link>http://m.tkk7.com/weidagang2046/articles/85980.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Wed, 06 Dec 2006 15:57:00 GMT</pubDate><guid>http://m.tkk7.com/weidagang2046/articles/85980.html</guid><wfw:comment>http://m.tkk7.com/weidagang2046/comments/85980.html</wfw:comment><comments>http://m.tkk7.com/weidagang2046/articles/85980.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/weidagang2046/comments/commentRss/85980.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/weidagang2046/services/trackbacks/85980.html</trackback:ping><description><![CDATA[ <p>~写高性能Web应用E序?0个入门技?br /><br /> (tng) 数据层性能 <br /> (tng) 技?1 ?q回多个l果?<br /> (tng) 技?2 ?分页的数据访?<br /> (tng) 技?3 ?q接?<br /> (tng) 技?4 ?ASP.NET ~存 API <br /> (tng) 技?5 ?每请求缓?<br /> (tng) 技?6 ?后台处理 <br /> (tng) 技?7 ?输出缓存和代理<a target="_blank">服务?/a><br /> (tng) 技?8 ?q行 IIS 6.0Q只要用于内核缓存)(j) <br /> (tng) 技?9 ?使用 Gzip 压羃 <br /> (tng) 技?10 ?<a target="_blank">服务?/a>控g视图状?<br /> (tng) <br /><br />使用 ASP.NET ~写 Web 应用E序的简单程度o(h)Z敢相信。正因ؓ(f)如此单,所以很?br />开发h员就不会(x)花时间来设计其应用程序的l构Q以获得更好的性能?jin)。在本文中,我将<br />讲述 10 个用于编写高性能 Web 应用E序的技巧。但是我q不?x)将q些仅局限于 <br />ASP.NET 应用E序Q因些应用程序只?Web 应用E序的一部分。本文不作ؓ(f)?Web <br />应用E序q行性能调整的权威性指??一整本书恐怕都无法L讲清楚这个问题。请?br />本文视作一个很好的L(fng)?<br /><br />成ؓ(f)工作狂之前,我原来喜Ƣ攀岩。在q行M大型攀岩活动之前,我都?x)首先仔l查?br />指南中的路线Q阅M前游客提出的。但是,无论指南怎么好,(zhn)都需要真正的攀?br />体验Q然后才能尝试一个特别具有挑战性的攀癅R与之相|当?zhn)面?f)修复性能问题或?br />q行一个高吞吐量站点的问题Ӟ(zhn)只能学?fn)如何编写高性能 Web 应用E序?br /><br />我的个h体验来自?Microsoft ?ASP.NET 部门作ؓ(f)基础架构E序l理的经验,在此?br />间我q行和管?www.ASP.NETQ帮助设计社?a target="_blank">服务?/a>的结构,C֌<a target="_blank">服务?/a>是几个著?<br />ASP.NET 应用E序Q组合到一个^台的 ASP.NET Forums?Text ?nGalleryQ。我信<br />有些曄帮助q我的技巧对(zhn)肯定也?x)有所帮助?br /><br />(zhn)应该考虑应用程序分为几个逻辑层。?zhn)可能听说q?3 层(或?n 层)(j)物理体系l构<br />一词。这些通常都是规定好的体系l构方式Q将功能在进E和/或硬件之间进行了(jin)物理分离<br />。当pȝ需要扩大时Q可以很L地添加更多的g。但是会(x)出现一个与q程和机器蟩?br />相关的性能下降Q因此应该避免。所以,如果可能的话Q请量在同一个应用程序中一?br />q行 ASP.NET 及(qing)其相关组件?br /><br />因ؓ(f)代码分离以及(qing)层之间的边界Q所以?Web 服务或远E处理将?x)得性能下降 20% <br />甚至更多?br /><br />数据层有点与众不同,因ؓ(f)通常情况下,最好具有专用于<a target="_blank">数据?/a>的硬件。然而进E蟩跃到<br /><a target="_blank">数据?/a>的成本依然很高,因此数据层的性能是?zhn)在优化代码时首先要考虑的问题?br /><br />在深入应用程序的性能修复问题之前Q请首先保对应用程序进行剖析,以便扑և具体?br />问题所在。主要性能计数器(如表C执行垃圑֛收所需旉癑ֈ比的计数器)(j)对于扑և?br />用程序在哪些位置p?jin)其主要旉也非常有用。然而花Ҏ(gu)间的位置通常非常不直观?br /><br />本文讲述?jin)两U类型的性能改善Q大型优化(如?ASP.NET ~存Q,和进行自w重复的<br />型优化。这些小型优化有时特别有意思。?zhn)对代码进行一点小的更改Q就?x)获得很?br />很多旉。用大型优化,(zhn)可能会(x)看到整体性能的较大飞跃。而用小型优化时Q对?br />某个特定h可能只会(x)节省几毫U的旉Q但是每天所有请求加hQ则可能?x)生巨?br />的改善?br /><br />数据层性能<br /><br /><br />谈到应用E序的性能调整Q有一个试U性的试可用来对工作q行优先U划分:(x)代码是否<br />讉K<a target="_blank">数据?/a>Q如果是Q频率是怎样的?h意,q一相同试也可应用于?Web 服务?br />q程处理的代码,但是本文对这些内Ҏ(gu)做讲q?br /><br />如果某个特定的代码\径中必需q行<a target="_blank">数据?/a>hQƈ且?zhn)认?f)要首先优化其他领域(如字<br />W串操作Q,则请停止Q然后执行这个试U性测试。如果?zhn)的性能问题不是非常严重的话<br />Q最好花一些时间来优化一下与<a target="_blank">数据?/a>、返回的数据量、进?a target="_blank">数据?/a>的往q频率相关的?br />Ҏ(gu)间?br /><br />?jin)解q些常规信息之后Q我们来看一下可能会(x)有助于提高应用程序性能的十个技巧。首?br />Q我要讲q可能会(x)引v最大改观的更改?br /><br /><br />技?1 ?q回多个l果?br /><br /><br />仔细查看(zhn)的<a target="_blank">数据?/a>代码Q看是否存在多次q入<a target="_blank">数据?/a>的请求\径。每个这L(fng)往q都?br />降低应用E序可以提供的每U请求数量。通过在一?a target="_blank">数据?/a>h中返回多个结果集Q可?br />节省?a target="_blank">数据?/a>q行通信所需的L间长度。同时因为减了(jin)<a target="_blank">数据?/a><a target="_blank">服务?/a>理h的工?br />Q还?x)得系l׾~性更强?br /><br />虽然可以使用动?SQL q回多个l果集,但是我首选用存储过E。关于业务逻辑是否?br />该驻留于存储q程的问题还存在一些争议,但是我认为,如果存储q程中的逻辑可以U束<br />q回数据的话Q羃?yu)数据集的大、羃短网l上所p旉Q不必筛选逻辑层的数据Q,<br />则应赞成q样做?br /><br />使用 SqlCommand 实例?qing)?ExecuteReader Ҏ(gu)填充强类型的业务cLQ可以通过调用 <br />NextResult 结果集指针向前Ud。图 1 昄?jin)用类型类填充几?ArrayList 的示?br />?x)话。只?a target="_blank">数据?/a>q回(zhn)需要的数据进一步减?a target="_blank">服务?/a>上的内存分配?<br /><br />Figure 1 Extracting Multiple Resultsets from a DataReader<br />// read the first resultset<br />reader = command.ExecuteReader();<br /><br />// read the data from that resultset<br />while (reader.Read()) {<br /> (tng) (tng) (tng) suppliers.Add(PopulateSupplierFromIDataReader( reader ));<br />}<br /><br />// read the next resultset<br />reader.NextResult();<br /><br />// read the data from that second resultset<br />while (reader.Read()) {<br /> (tng) (tng) (tng) products.Add(PopulateProductFromIDataReader( reader ));<br />}<br /><br /><br />技?2 ?分页的数据访?br /><br /><br />ASP.NET DataGrid h一个很好的功能Q数据分|持。在 DataGrid 中启用分|Q一<br />ơ会(x)昄固定数量的记录。另外,?DataGrid 的底部还?x)显C分?UIQ以便在记录之间<br />q行D。该分页 UI 使?zhn)能够在所昄的数据之间向前和向后DQƈ且一ơ显C固?br />数量的记录?br /><br />q有一个小的波折。?DataGrid 的分需要所有数据均与网D行绑定。例如,(zhn)?br />的数据层需要返回所有数据,那么 DataGrid ׃(x)Z当前늭选显C的所有记录。如?br />通过 DataGrid q行分页时返回了(jin) 100,000 个记录,那么针对每个h?x)放?99,975 ?br />记录Q假设每大ؓ(f) 25 个记录)(j)。当记录的数量不断增加时Q应用程序的性能׃(x)?br />到媄(jing)响,因ؓ(f)针对每个h必须发送越来越多的数据?br /><br />要编写性能更好的分代码,一个极佳的方式是用存储过E。图 2 昄?jin)针?<br />Northwind <a target="_blank">数据?/a>中的 Orders 表进行分늚一个示例存储过E。简而言之,(zhn)此时要?br />的只是传递页索引和页大小。然后就?x)计合适的l果集,q将其返回?<br /><br />Figure 2 Paging Through the Orders Table<br />CREATE PROCEDURE northwind_OrdersPaged<br />(<br /> (tng) (tng) (tng) @PageIndex int, <br /> (tng) (tng) (tng) @PageSize int<br />)<br />AS<br />BEGIN<br />DECLARE @PageLowerBound int<br />DECLARE @PageUpperBound int<br />DECLARE @RowsToReturn int<br /><br />-- First set the rowcount<br />SET @RowsToReturn = @PageSize * (@PageIndex + 1)<br />SET ROWCOUNT @RowsToReturn<br /><br />-- Set the page bounds<br />SET @PageLowerBound = @PageSize * @PageIndex<br />SET @PageUpperBound = @PageLowerBound + @PageSize + 1<br /><br />-- Create a temp table to store the select results<br />CREATE TABLE #PageIndex <br />(<br /> (tng) (tng) (tng) IndexId int IDENTITY (1, 1) NOT NULL,<br /> (tng) (tng) (tng) OrderID int<br />)<br /><br />-- Insert into the temp table<br />INSERT INTO #PageIndex (OrderID)<br />SELECT <br /> (tng) (tng) (tng) OrderID<br />FROM <br /> (tng) (tng) (tng) Orders<br />ORDER BY <br /> (tng) (tng) (tng) OrderID DESC<br /><br />-- Return total count<br />SELECT COUNT(OrderID) FROM Orders<br /><br />-- Return paged results<br />SELECT <br /> (tng) (tng) (tng) O.*<br />FROM <br /> (tng) (tng) (tng) Orders O,<br /> (tng) (tng) (tng) #PageIndex PageIndex<br />WHERE <br /> (tng) (tng) (tng) O.OrderID = PageIndex.OrderID AND<br /> (tng) (tng) (tng) PageIndex.IndexID > @PageLowerBound AND<br /> (tng) (tng) (tng) PageIndex.IndexID < @PageUpperBound<br />ORDER BY <br /> (tng) (tng) (tng) PageIndex.IndexID<br /><br />END<br /><br /><br /><br />在社?a target="_blank">服务?/a>中,我们~写?jin)一个分?a target="_blank">服务?/a>控gQ以完成所有的数据分页。?zhn)?x)看到<br />Q我使用的就是技?1 中讨论的理念Q从一个存储过E返回两个结果集Q记录的L和请<br />求的数据?br /><br />q回记录的L可能?x)根据所执行查询的不同而有所变化。例如,W(xu)HERE 子句可用来约?br />q回的数据。ؓ(f)?jin)计在分?UI 中显C的总页敎ͼ必须?jin)解要返回记录的L。例如,<br />如果d?1,000,000 条记录,q且要用一?WHERE 子句其{选ؓ(f) 1000 条记录,<br />那么分页逻辑需要了(jin)解记录的L才能正确呈现分页 UI?br /><br /><br />技?3 ?q接?br /><br /><br />?Web 应用E序?<a target="_blank">SQL Server</a>? 之间讄 TCP q接可能是一个非常消耗资源的操作。Mi<br />crosoft 的开发h员到目前为止能够使用q接池已l有一D|间了(jin)Q这使得他们能够重用<br /><a target="_blank">数据?/a>q接。他们不是针Ҏ(gu)个请求都讄一个新?TCP q接Q而是只在q接池中没有?br />何连接时才设|新q接。当q接关闭Ӟ它会(x)q回q接池,在其中它?x)保持?a target="_blank">数据?/a>的连<br />接,而不是完全破坏该 TCP q接?br /><br />当然Q?zhn)需要小?j)是否?x)出现泄漏q接。当(zhn)完成用连接时Q请一定要关闭q些q接?br />再重复一遍:(x)无论M人对 Microsoft?.NET Framework 中的垃圾回收有什么评论,请一<br />定要在完成用连接时针对该连接显式调?Close ?Dispose。不要相信公paq行?br />(CLR) ?x)在预先定的时间?f)(zhn)清除和关闭q接。尽?CLR 最l会(x)破坏该类Qƈ强制q?br />接关闭,但是当针对对象的垃圾回收真正发生Ӟq不能保证?<br /><br />要以最优化的方式用连接池Q需要遵守一些规则。首先打开q接Q执行操作,然后关闭<br />该连接。如果?zhn)必须如此的话Q可以针Ҏ(gu)个请求多ơ打开和关闭连接(最好应用技?1<br />Q,但是不要一直将q接保持打开状态ƈ使用各种不同的方法对其进行进Z递。第二,<br />使用相同的连接字W串Q如果用集成n份验证的话,q要使用相同的线E标识)(j)。如?br />不用相同的q接字符Ԍ例如Ҏ(gu)d的用戯定义q接字符Ԍ那么(zhn)将无法得到q?br />接池提供的同一个优化倹{如果?zhn)使用集成w䆾验证Q同时还要模拟大量用Pq接池的<br />效率也会(x)大大下降。尝试跟t与q接池相关的M性能问题Ӟ.NET CLR 数据性能计数?br />可能非常有用?<br /><br />每当应用E序q接资源Ӟ如在另一个进E中q行?a target="_blank">数据?/a>Q?zhn)都应该重点考虑q接该资<br />源所花时间、发送或(g)索数据所花时_(d)以及(qing)往q的数量Q从而进行优化。优化应用程?br />中Q何种cȝq程跌都是获得更佳性能的首要一炏V?br /><br />应用层包含了(jin)q接数据层、将数据转换为有意义cd例和业务程的逻辑。例如社区服?br />器,(zhn)要在其中填充Forums ?Threads集合Q应用业务规则(如权限)(j)Q最重要的是要在<br />其中执行~存逻辑?br /><br /><br />技?4 ?ASP.NET ~存 API<br /><br /><br />~写应用E序代码行之前,一个首要完成的操作是设计应用层的结构,以便最大化利用 <br />ASP.NET ~存功能?br /><br />如果(zhn)的lg要在 ASP.NET 应用E序中运行,则只需在该应用E序目中包括一?<br />System.Web.dll 引用。当(zhn)需要访问该~存Ӟ请?HttpRuntime.Cache 属性(通过 <br />Page.Cache ?HttpContext.Cache 也可讉Kq个对象Q?br /><br />对于~存数据Q有几个规则。首先,如果数据可能?x)多ơ用时Q则q是使用~存的一?br />很好的备选情c(din)第二,如果数据是通用的,而不特定于某个具体的h或用hQ则?br />是用缓存的一个很好的备选情c(din)如果数据是特定于用hh的,但是寿命较长的话<br />Q仍然可以对其进行缓存,但是q种情况可能q不l常使用。第三,一个经常被忽略的规<br />则是Q有时可能?zhn)~存得太多。通常在一?x86 计算ZQؓ(f)?jin)减内存不错误出现?br />Z(x)Q?zhn)会(x)想使用不高?800MB 的专用字节运行进E。因此缓存应该有个限度。换句话?br />Q?zhn)可能能够重用某个计算l果Q但是如果该计算采用 10 个参数的话,(zhn)可能要试~?br />?10 个排列,q样有可能给(zhn)带来麻?ch)。一个要?ASP.NET 的最常见支持是由于过度缓<br />存引L(fng)内存不错误Q尤其是对于大型数据集?br /><br /><br />~存有几个极佳的功能Q?zhn)需要对它们有所?jin)解。首先,~存?x)实现最q最用的法<br />Q?ASP.NET 能够在内存运行效率较低的情况下强制缓存清?Q?从缓存自动删除未?br />用过的项目。第二,~存支持可以强制失效的过期依赖项。这些依赖项包括旉、密钥和<br />文g。时间经怼(x)用到Q但是对?ASP.NET 2.0Q引入了(jin)一个功能更强的新失效类型:(x)?br />据库~存失效。它指的是当<a target="_blank">数据?/a>中的数据发生变化时自动删除缓存中的项。有?a target="_blank">数据?/a><br />~存失效的详l信息,请参?MSDN?Magazine 2004 q?7 月的 Dino Esposito Cutting <br />Edge 专栏。要?jin)解~存的体pȝ构,请参阅图 3?br /><br />技?5 ?每请求缓?br /><br />在本文前面部分,我提C(jin)l常遍历代码路径的一些小改善可能?x)导致较大的整体性能?br />益。对于这些小改善Q其中有一个绝Ҏ(gu)我的最爱,我将其称之ؓ(f)"每请求缓??br /><br />~存 API 的设计目的是Z(jin)数据缓存较长的一D|_(d)或者缓存至满某些条gӞ?br />每请求缓存则意味着只将数据~存h的持l时间。对于每个请求,要经常访问某?br />特定的代码\径,但是数据却只需提取、应用、修Ҏ(gu)更新一ơ。这听v来有些理论化Q?br />那么我们来D一个具体的CZ?br /><br />在社?a target="_blank">服务?/a>的论坛应用程序中Q页面上使用的每?a target="_blank">服务?/a>控g都需要个性化的数据来?br />定用什么外观、用什么样式表Q以?qing)其他个性化数据。这些数据中有些可以长期~存<br />Q但是有些数据却只针Ҏ(gu)个请求提取一ơ,然后在执行该h期间对其重用多次Q如?br />用于控g的外观?br /><br />Z(jin)辑ֈ每请求缓存,请?ASP.NET HttpContext。对于每个请求,都会(x)创徏一?<br />HttpContext 实例Q在该请求期间从 HttpContext.Current 属性的M位置都可讉K该实<br />例。该 HttpContext cd有一个特D的 Items 集合属性;d到此 Items 集合的对象和<br />数据只在该请求持l期间内q行~存。正如?zhn)可以使用~存来存储经常访问的数据一P<br />(zhn)也可以使用 HttpContext.Items 来存储只Z每个h使用的数据。它背后的逻辑非常<br />单:(x)数据在它不存在的时候添加到 HttpContext.Items 集合Q在后来的查找中Q只是返<br />?HttpContext.Items 中的数据?br /><br /><br />技?6 ?后台处理<br /><br /><br />通往代码的\径应该尽可能快速,是吗Q可能有时?zhn)会(x)觉得针?gu)个请求执行的或者每 <br />n 个请求执行一ơ的d所需资源非常多。发送电(sh)子邮件或者分析和验证传入数据是q?br />L(fng)一些例子?br /><br />剖析 ASP.NET Forums 1.0 q新构建组成社?a target="_blank">服务?/a>的内Ҏ(gu)Q我们发现添加新张脓(chung)?br />代码路径非常慢。每ơ添加新张脓(chung)Ӟ应用E序首先需要确保没有重复的张脓(chung)Q然后必?br />使用"坏词"{选器分析该张_(d)分析张脓(chung)的字W图释,对张贴添加标记ƈq行索引Q请?br />时将张脓(chung)d到合适的队列Q验证附Ӟ最l张贴之后,立即向所有订阅者发出电(sh)子邮?br />通知。很清楚Q这涉及(qing)很多操作?br /><br />l研I发玎ͼ大多数时间都花在?jin)?ch)引逻辑和发送电(sh)子邮件上。对张脓(chung)q行索引是一个非<br />常耗时的操作,Z发现内置?System.Web.Mail 功能要连?SMYP <a target="_blank">服务?/a>Q然后连l发<br />送电(sh)子邮件。当某个特定张脓(chung)或主题领域的订阅者数量增加时Q执?AddPost 功能所需?br />旉也越来越ѝ?br /><br />q不需要针Ҏ(gu)个请求都q行?sh)子邮g索引。理x况下Q我们想要将此操作进行批处理<br />Q一ơ烦(ch)?25 个张贴或者每五分钟发送一ơ所有电(sh)子邮件。我们决定用以前用于对?br />据缓存失效进行原型设计的代码Q这个失效是用于最l进?Visual Studio? 2005 的内?br />的?br /><br />System.Threading 命名I间中的 Timer c非常有用,但是?.NET Framework 中不是很<br />有名Q至对?Web 开发h员来说是q样。创Z后,q个 Timer cd以一个可配置?br />间隔针对 ThreadPool 中的某个U程调用指定的回调。这pC,(zhn)可以对代码q行讄<br />Q其能够在没有?ASP.NET 应用E序q行传入h的情况下得以执行Q这是后台处理的<br />理想情况。?zhn)q可以在此后台进E中执行如烦(ch)引或发送电(sh)子邮件之cȝ操作?<br /><br />但是Q这一技术有几个问题。如果应用程序域卸蝲Q该计时器实例将停止触发其事件。另<br />外,因ؓ(f) CLR 对于每个q程的线E数量具有一个硬性标准,所以可能会(x)出现q样的情形:(x)<br /><a target="_blank">服务?/a>负蝲很重Q其中计时器可能没有可在其基上得以完成的U程Q在某种E度上可?br />?x)造成延迟。ASP.NET 通过在进E中保留一定数量的可用U程Qƈ且仅使用ȝE的一?br />分用于请求处理,试图上q情况发生的Z(x)降到最低。但是,如果(zhn)具有很多异步操?br />Ӟq可能就是一个问题了(jin)?<br /><br />q里没有_的空间来攄该代码,但是(zhn)可以下载一个可以看懂的CZQ网址?<br />www.rob-howard.net。请?jin)解一?Blackbelt TechEd 2004 演示中的qȝ片和演示?br /><br /><br />技?7 ?输出缓存和代理<a target="_blank">服务?/a><br /><br /><br />ASP.NET 是?zhn)的表C层Q或者说应该是?zhn)的表C层Q;它由c(din)用h件?a target="_blank">服务?/a>控gQH<br />ttpHandlers ?HttpModulesQ以?qing)它们生成的内容l成。如果?zhn)h一?ASP.NET ,<br />它会(x)生成输出QHTML、XML、图像或M其他数据Q,q且(zhn)针Ҏ(gu)个请求运行此代码Ӟ<br />它都?x)生成相同的输出Q那么?zhn)拥有一个可用于输出缓存的l佳备选内宏V?<br /><br />此行内Ҏ(gu)加页的最上端 <br /><br /><%@ Page OutputCache VaryByParams="none" Duration="60" %> <br /><br />可以高效地为此는成一ơ输出,然后对它q行多次重用Q时间最长ؓ(f) 60 U,此时?br />将重新执行Q输Z再一ơ添加到 ASP.NET ~存。通过使用一些低U程序化 API ?br />可以完成此行为。对于输出缓存有几个可配|的讄Q如刚刚讲到?VaryByParams 属?br />。VaryByParams 刚好被请求到Q但q允许?zhn)指?HTTP GET ?HTTP POST 参数来更改缓<br />存项。例如,只需讄 VaryByParam="Report" 卛_?default.aspx?Report=1 ?<br />default.aspx?Report=2 q行输出~存。通过指定一个以分号分隔的列表,q可以指定其<br />他参数?<br /><br />很多人都不知道何时用输出缓存,ASP.NET 还?x)生成一些位于缓?a target="_blank">服务?/a>下游?<br />HTTP 标头Q如 Microsoft Internet Security and Acceleration Server ?Akamai ?br />用的标头。设|了(jin) HTTP ~存标头之后Q可以在q些|络资源上对文档q行~存Q客L(fng)<br />h也可在不必返回原?a target="_blank">服务?/a>的情况下得以满?br /><br />因此Q用页输出~存不会(x)使得(zhn)的应用E序效率更高Q但是它可能?x)减?a target="_blank">服务?/a>上的?br />载,因ؓ(f)下游~存技术会(x)~存文档。当?dng)q可能只是匿名内容;一旦它成ؓ(f)下游之后Q?br />(zhn)就再也不会(x)看到q些hQƈ且再也无法执行n份验证以L对它的访问了(jin)?br /><br /><br />技?8 ?q行 IIS 6.0Q只要用于内核缓存)(j)<br /><br /><br />如果(zhn)未q行 IIS 6.0 (<a target="_blank">Windows</a> Server? 2003)Q那么?zhn)错q了(jin) Microsoft Web 服务<br />器中的一些很好的性能增强。在技?7 中,我讨Z(jin)输出~存。在 IIS 5.0 中,h?br />通过 IIS 然后q入 ASP.NET 的。涉?qing)到~存ӞASP.NET 中的 HttpModule ?x)接收该?br />求,q返回缓存中的内宏V?br /><br />如果(zhn)正在?IIS 6.0Q就?x)发C个很好的功能,UCؓ(f)内核~存Q它不需要对 <br />ASP.NET q行M代码更改。当h?ASP.NET q行输出~存ӞIIS 内核~存?x)接收?br />存数据的一个副本。当h来自|络驱动E序Ӟ内核U别的驱动程序(无上下文切换?br />用户模式Q就?x)接收该hQ如果经q了(jin)~存Q则?x)将~存的数据刷新到响应Q然后完?br />执行。这pC,当?zhn)内核模式缓存?IIS ?ASP.NET 输出~存一起用时Q就?x)?br />Co(h)Z敢相信的性能l果。在 ASP.NET ?Visual Studio 2005 开发过E中Q我一度是<br />负责 ASP.NET 性能的程序经理。开发h员完成具体工作,但是我要看到每天q行的所有报<br />告。内核模式缓存结果L最有意思的。最常见的特征是|络充满?jin)请?响应Q?IIS <br />q行时的 CPU 使用率只有大U?5%。这太o(h)人震惊了(jin)Q当然?IIS 6.0 q有一些其他原<br />因,但是内核模式~存是其中最明显的一个?br /><br /><br />技?9 ?使用 Gzip 压羃<br /><br /><br />虽然使用 gzip q不一定是<a target="_blank">服务?/a>性能技巧(因ؓ(f)(zhn)可能会(x)看到 CPU 使用率的提高Q,?br />是?gzip 压羃可以减少<a target="_blank">服务?/a>发送的字节数量。这׃Z觉得速度加快?jin),q且<br />q减了(jin)带宽的用量。根据所发送数据、可以压~的E度以及(qing)客户端浏览器是否支持QIIS<br />只会(x)向支?gzip 压羃的客L(fng)发送经q?gzip 压羃的内容,?Internet Explorer <br />6.0 ?FirefoxQ,(zhn)的<a target="_blank">服务?/a>每秒可以服务于更多的h。实际上Q几乎每当?zhn)减少所<br />q回数据的数量时Q都?x)增加每U请求数?<br /><br />Gzip 压羃已经内置?IIS 6.0 中,q且其性能?IIS 5.0 中用的 gzip 压羃要好的多<br />Q这是好消息。但不幸的是Q当试?IIS 6.0 中打开 gzip 压羃Ӟ(zhn)可能无法在 <br />IIS 的属性对话中扑ֈ该设|。IIS 组在该<a target="_blank">服务?/a>中置入了(jin)卓越?gzip 功能Q但是忘<br />?jin)包括一个用于启用该功能的管?UI。要启用 gzip 压羃Q?zhn)必须深入?IIS 6.0 ?<br />XML 配置讄内部Q这样不?x)引起?j)脏虚弱)(j)。顺便提一句,q归功于 OrcsWeb ?<br />Scott ForsythQ他帮助我提Z(jin)?OrcsWeb 上宿ȝ www.asp.net <a target="_blank">服务?/a>的这个问题?br /><br /><br />本文׃讲述步骤?jin),请阅?Brad Wilson 的文章,|址?IIS6 Compression。还有一<br />有关ؓ(f) ASPX 启用压羃的知识库文章Q网址?Enable ASPX Compression in IIS。但?br />(zhn)应该注意,׃一些实施细节,IIS 6.0 中不能同时存在动态压~和内核~存?br /><br /><br />技?10 ?<a target="_blank">服务?/a>控g视图状?br /><br /><br />视图状态是一个有的名称Q用于表C在所生成늚隐藏输出字段中存储一些状态数据的 <br />ASP.NET。当该页张脓(chung)?a target="_blank">服务?/a>Ӟ<a target="_blank">服务?/a>可以分析、验证、ƈ此视图状态数据应用回?br />늚控g?wi)。视囄态是一个非常强大的功能Q因为它允许状态与客户端一起保持,q且<br />它不需?cookie ?a target="_blank">服务?/a>内存卛_保存此状态。很?ASP.NET <a target="_blank">服务?/a>控g都用视囄<br />态来保持在与元素进行交互期间创建的讄Q例如保存对数据q行分页时显C的当前?br />?<br /><br />然而用视囄态也有一些缺炏V首先,服务或请求页Ӟ它都?x)增加页的总负载。对?br />贴回<a target="_blank">服务?/a>的视囄态数据进行序列化或取消序列化Ӟ也会(x)发生额外的开销。最后,?br />囄态会(x)增加<a target="_blank">服务?/a>上的内存分配?br /><br />几个<a target="_blank">服务?/a>控g有着q度使用视图状态的势Q即使在q不需要的情况下也要用它Q其<br />中最著名的是 DataGrid。ViewState 属性的默认行ؓ(f)是启用,但是如果(zhn)不需要,则可?br />在控件或别关闭。在控g内,只需?EnableViewState 属性设|ؓ(f) falseQ或者在?br />中用下列设|即可对其进行全局讄Q?<br /><br /><%@ Page EnableViewState="false" %><br /><br />如果(zhn)不回发,或者L针对每个h重新生成上的控Ӟ则应该在别禁用视?br />状态?<br /><br /><br />我ؓ(f)(zhn)讲qC(jin)一些我认ؓ(f)在编写高性能 ASP.NET 应用E序时有所帮助的技巧。正如我在本<br />文前面部分提到的那样Q这是一个初步指南,q不?ASP.NET 性能的最后结果。(有关?br />?ASP.NET 应用E序性能的信息,请参?Improving ASP.NET Performance。)(j)只有通过<br />自己的亲w体验才能找?gu)军_体性能问题的最好方法。但是,在?zhn)的旅E中Q这些技?br />应该?x)?f)(zhn)提供一些好的指南。在软g开发中Q几乎没有绝对的东西Q每个应用程序都?br />唯一的?br /><br />from: <a >http://www.chinahtml.com/programming/8/2006/11622676777784_2.shtml</a><br /></p> <img src ="http://m.tkk7.com/weidagang2046/aggbug/85980.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/weidagang2046/" target="_blank">weidagang2046</a> 2006-12-06 23:57 <a href="http://m.tkk7.com/weidagang2046/articles/85980.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>linux下postgresql数据库中汉字的插?/title><link>http://m.tkk7.com/weidagang2046/articles/85213.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Sun, 03 Dec 2006 11:55:00 GMT</pubDate><guid>http://m.tkk7.com/weidagang2046/articles/85213.html</guid><wfw:comment>http://m.tkk7.com/weidagang2046/comments/85213.html</wfw:comment><comments>http://m.tkk7.com/weidagang2046/articles/85213.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/weidagang2046/comments/commentRss/85213.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/weidagang2046/services/trackbacks/85213.html</trackback:ping><description><![CDATA[首先用postgresql的用L(fng)?(su - postgres) ,然后q入数据?假设数据库名UCؓ(f)“house?命o(h)?<br /><br />[postgres@ITC-S postgres]$ psql house<br />Welcome to psql 8.0.1, the PostgreSQL interactive terminal.<br /><p>Type: (tng) copyright for distribution terms<br />  (tng) (tng) (tng) (tng) (tng) (tng) h for help with SQL commands<br />  (tng) (tng) (tng) (tng) (tng) (tng) ? for help with psql commands<br />  (tng) (tng) (tng) (tng) (tng) (tng) g or terminate with semicolon to execute query<br />  (tng) (tng) (tng) (tng) (tng) (tng) q to quit<br />house=# <br />输入encoding GBK<br />house=#set encoding GBK<br />然后可以插入汉字了(jin)?br /><br />from: <a >http://publish.it168.com/2006/0219/20060219173801.shtml?positioncode=1547</a></p><img src ="http://m.tkk7.com/weidagang2046/aggbug/85213.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/weidagang2046/" target="_blank">weidagang2046</a> 2006-12-03 19:55 <a href="http://m.tkk7.com/weidagang2046/articles/85213.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一x逸的数据库编码解x?/title><link>http://m.tkk7.com/weidagang2046/articles/85178.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Sun, 03 Dec 2006 05:22:00 GMT</pubDate><guid>http://m.tkk7.com/weidagang2046/articles/85178.html</guid><wfw:comment>http://m.tkk7.com/weidagang2046/comments/85178.html</wfw:comment><comments>http://m.tkk7.com/weidagang2046/articles/85178.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/weidagang2046/comments/commentRss/85178.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/weidagang2046/services/trackbacks/85178.html</trackback:ping><description><![CDATA[ <p>  <strong>问题提出</strong></p> <p>  现在几乎所有的应用pȝ都无法避免用数据库pȝ。在JAVA世界里访问数据库是一仉常轻杄事情QJDBC为JAVA应用E序讉K数据库提供了(jin)一个统一的接口,通过使用JDBC接口开发者无需兛_(j)pȝ最l采用哪U数据库Q因为JDBC仅仅是定义了(jin)讉K几个JAVA的接口类Q具体的实现是由数据库厂商提供的Q这U做法其实与其他数据库连接方式例如ODBC是类似的。但是在实际的应用过E中Q开发者发现离JDBC设计的初衯是有一定距,比如说在存储字W串时的~码问题Q我惛_多开发者都?x)遇见这个问题,倒不是因解决它有什么技术方面的隑ֺQ而是它的的确非常繁琐。我们必d每次写入或者读出字W串的时候进行编码和反编码处理;或者说我们可以写一个方法可以进行编码处理的Q但又必d每次数据库操作的时候调用,虽然调用很简单,可是我非得这样吗Q要是忘?jin)编码那又要DEBUG?jin)。当然你可能觉得qƈ没有什么,或者你可能很勤快,喜欢写大量重复的代码Q可是你N没有觉得q种J琐的工作正在浪费你q于宝贵的青春吗Q停止你的键盘输入,让我们来解决q个问题吧!</p> <p>  <strong>解决思\</strong></p> <p>  在传l的应用E序中数据库操作部分我们可以惌成两层,如图所C:(x)一个是数据库的"q接?Q另外一个业务数据操作层。在q里数据库的q接池是q义的,你可以把JDBC中的DriverManager也当成是q接池,具体的意思就是我们可以通过q层来获取到指定数据库的q接而不d?j)它是怎么获取的。如果这个时候数据库pȝQ有如InformixQSQL ServerQ要求对字符串进行{码才能存储(例如最常见的GBK->ISO8859_1转码Q,那我们就必须在业务数据操作层来进行,q样有多业务数据操作我们就要做多少~码转码的工作,太麻?ch)?jin)Q代码中充斥中大量重复的内容。本文提出的解决Ҏ(gu)是利用对获取到的数据库q接实例q行二次装Q也是在数据库q接池与业务数据操作层之间加入了(jin)q接装层,当然?jin),我们也完全可以直接将q接装集成到数据库q接池内部。关于连接池的实现请参照我的另外一文章《用JAVA动态代理实现数据库q接池?/p> <p align="center"> <img height="173" src="http://www.javafan.net/uploadfiles/20041212111952100.gif" width="247" border="0" /> <br />图一</p> <p>  我们知道q行~码和{码工作都是集中在JDBC的两个接口PreparedStatement和ResultSet上进行的Q主要涉?qing)PreparedStatement的setStringҎ(gu)以及(qing)ResultSet的getStringҎ(gu)。前面我们讲q需要加入一个连接封装层来对数据库连接实例进行二ơ封装,但是怎么通过q个装来改变PreparedStatement和ResultSetq两个接口的行ؓ(f)呢?q个问题其实也很单,因ؓ(f)PreparedStatement接口必须通过Connection接口来获取实例,而ResultSet接口又必MStatement或者PreparedStatement接口来获取实例,有了(jin)q样的联关p,问题也就q刃而解?jin)。还是利用我在文章《用JAVA动态代理实现数据库q接池》中使用的动态接口代理技术。首先我们设计Connection接口的代理类_ConnectionQ这个代理类接管?jin)Connection接口中所有可能获取到Statement或者PreparedStatement接口实例的方法,例如QprepareStatement和createStatement。改变这两个Ҏ(gu)使之q回的是l过接管后的Statement或者PreparedStatement实例。通过对于Statement接口也有相应的代理类_StatementQ这个代理类接管用于获取ResultSet接口实例的所有方法,包括对setStringҎ(gu)的接以军_是否对字W串q行~码处理。对于接口ResultSet的接类_ResultSetq应的比较单,它只需要处理getStringҎ(gu)卛_?/p> <p>  <strong>关键代码</strong></p> <p>  前面我们大概介绍?jin)这个解x案的思\Q下面我们给出关键的实现代码包括Connection的代理类QStatement的代理类QResultSet的代理类。这些代码是在原来关于数据库q接池实现的基础上进行扩充之增加对自动~码处理的功能。有需要源码打包的可以通过?sh)子邮g跟我联系?/p> <p>_Connection.java</p> <p style="BACKGROUND: #eeeeee">/* <br /> (tng)* Created on 2003-10-23 by Liudong <br /> (tng)*/<br />package lius.pool;<br />import java.sql.*;<br />import java.lang.reflect.*;<br /><br />/*<br /> (tng)* <br /> (tng)* 数据库连接的代理c?<br /> (tng)* @author Liudong <br /> (tng)*/<br /> (tng)class _Connection implements InvocationHandler{<br /> (tng)private Connection conn = null;<br /> (tng)private boolean coding = false;<br /> (tng)//指定是否q行字符串{码操?br /> (tng)_Connection(Connection conn, boolean coding){<br /> (tng) (tng)this.conn = conn;<br /> (tng) (tng)this.coding = coding;<br /> (tng) (tng)initConnectionParam(this.conn);<br /> (tng)<br /> (tng)}<br /> (tng)<br /> (tng)/** (tng) <br /> (tng) * Returns the conn. (tng) <br /> (tng) * @return Connection (tng) <br /> (tng) */<br /> (tng) <br /> (tng)public Connection getConnection() {<br /> (tng) (tng)Class[] interfaces = conn.getClass().getInterfaces();<br /> (tng) (tng)if(interfaces==null||interfaces.length==0){<br /> (tng) (tng) (tng)interfaces = new Class[1];<br /> (tng) (tng) (tng)interfaces[0] = Connection.class;<br /> (tng) (tng)<br /> (tng) (tng)}<br /> (tng)<br /> (tng) (tng)Connection conn2 = (Connection)Proxy.newProxyInstance( (tng)conn.getClass().getClassLoader(), interfaces,this);<br /> (tng) (tng)return conn2;<br /> (tng)<br /> (tng)}<br /> (tng)<br /> (tng)/** (tng) <br /> (tng) * @see java.lang.reflect.InvocationHandler#invoke (tng) <br /> (tng) */<br /> (tng)public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { (tng)<br /> (tng) (tng)String method = m.getName();<br /> (tng) (tng)//调用相应的操?br /> (tng) (tng)Object obj = null;<br /> (tng) (tng)try{<br /> (tng) (tng) (tng)obj = m.invoke(conn, args);<br /> (tng) (tng) (tng)//接管用于获取语句句柄实例的方?br /> (tng) (tng) (tng)if((CS.equals(method)||PS.equals(method))&&coding) <br /> (tng) (tng) (tng) (tng)return new _Statement((Statement)obj,true).getStatement();<br /> (tng) (tng)<br /> (tng) (tng)} catch(InvocationTargetException e) {<br /> (tng) (tng) (tng)throw e.getTargetException();<br /> (tng) (tng)}<br /> (tng) (tng)return obj;<br /> (tng)}<br /> (tng)<br /> (tng)private final static String PS = "prepareStatement";<br /> (tng)private final static String CS = "createStatement";<br />}</p> <p> <br />_Statement.java</p> <p style="BACKGROUND: #eeeeee">/* <br /> (tng)* Created on 2003-10-23 by Liudong <br /> (tng)*/<br /> (tng)<br />package lius.pool;<br />import java.sql.*;<br />import java.lang.reflect.*;<br /><br />/** <br /> (tng)* 数据库语句对象实例的代理c?<br /> (tng)* @author Liudong <br /> (tng)*/<br />class _Statement implements InvocationHandler{ (tng)<br /> (tng)private Statement statement ; //保存所接管对象的实例?br /> (tng)private boolean decode = false; //指定是否q行字符串{码?br /><br /> (tng)public _Statement(Statement stmt,boolean decode) { (tng)<br /> (tng) (tng)this.statement = stmt;<br /> (tng) (tng)this.decode = decode;<br /> (tng)}<br /> (tng)<br /> (tng)/** (tng) <br /> (tng) * 获取一个接后的对象实例?<br /> (tng) * @return (tng) <br /> (tng) */<br /> (tng)public Statement getStatement() {<br /> (tng) (tng)Class[] interfaces = statement.getClass().getInterfaces();<br /> (tng) (tng)if(interfaces==null||interfaces.length==0){ (tng)<br /> (tng) (tng) (tng)interfaces = new Class[1];<br /> (tng) (tng) (tng)interfaces[0] = Statement.class;<br /> (tng) (tng)} (tng)<br /> (tng) (tng)Statement stmt = (Statement)Proxy.newProxyInstance( (tng) (tng) (tng)<br /> (tng) (tng) (tng)statement.getClass().getClassLoader(), (tng)<br /> (tng) (tng) (tng)interfaces,this);<br /> (tng) (tng)return stmt;<br /> (tng)<br /> (tng)}<br /> (tng)<br /> (tng)/** (tng) <br /> (tng) * Ҏ(gu)接管 (tng) <br /> (tng) */<br /> (tng)public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {<br /> (tng) (tng)String method = m.getName(); //接管setStringҎ(gu) (tng)<br /> (tng) (tng)if(decode && SETSTRING.equals(method)) {<br /> (tng) (tng) (tng)try{<br /> (tng) (tng) (tng) (tng)String param = (String)args[1];<br /> (tng) (tng) (tng) (tng)if(param!=null)<br /> (tng) (tng) (tng) (tng) (tng)param = new String(param.getBytes(),"8859_1");<br /> (tng) (tng) (tng) (tng)return m.invoke(statement,new Object[]{args[0],param});<br /> (tng) (tng) (tng)} catch(InvocationTargetException e){<br /> (tng) (tng) (tng) (tng)throw e.getTargetException();<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)<br /> (tng) (tng) (tng)} (tng) (tng)<br /> (tng) (tng)}<br /> (tng) (tng)<br /> (tng) (tng)//接管executeQueryҎ(gu)<br /> (tng) (tng)<br /> (tng) (tng)if(decode && EXECUTEQUERY.equals(method)){<br /> (tng) (tng) (tng)try{<br /> (tng) (tng) (tng) (tng)ResultSet rs = (ResultSet)m.invoke(statement,args);<br /> (tng) (tng) (tng) (tng)return new _ResultSet(rs,decode).getResultSet();<br /> (tng) (tng) (tng)<br /> (tng) (tng) (tng)}catch(InvocationTargetException e){<br /> (tng) (tng) (tng) (tng)throw e.getTargetException();<br /> (tng) (tng) (tng) (tng)} (tng) (tng)<br /> (tng) (tng)}<br /> (tng) (tng)<br /> (tng) (tng)try{<br /> (tng) (tng) (tng)return m.invoke(statement, args);<br /> (tng) (tng)} catch(InvocationTargetException e) {<br /> (tng) (tng) (tng)throw e.getTargetException();<br /> (tng) (tng) (tng)} (tng)<br /> (tng)}<br /> (tng)//两个要接的Ҏ(gu)?br /> (tng)<br /> (tng)private final static String SETSTRING = "setString";<br /> (tng)private final static String EXECUTEQUERY = "executeQuery";<br />}</p> <p> <br />_ResultSet.java</p> <p style="BACKGROUND: #eeeeee">/* <br /> (tng)* Created on 2003-10-23 by Liudong <br /> (tng)*/<br /> (tng)<br />package lius.pool;<br />import java.sql.ResultSet;<br />import java.lang.reflect.InvocationHandler;<br />import java.lang.reflect.InvocationTargetException;<br />import java.lang.reflect.Method;<br />import java.lang.reflect.Proxy;<br /><br />/** <br /> (tng)* 数据库结果集的代理类 <br /> (tng)* @author Liudong <br /> (tng)*/<br /> (tng)class _ResultSet implements InvocationHandler{ (tng)<br /> (tng)private ResultSet rs = null;<br /> (tng)private boolean decode = false;<br /> (tng)<br /> (tng)public _ResultSet(ResultSet rs,boolean decode) {<br /> (tng) (tng)this.rs = rs;<br /> (tng) (tng)this.decode = decode;<br /> (tng)}<br /> (tng)<br /> (tng)public ResultSet getResultSet(){ (tng)<br /> (tng) (tng)Class[] interfaces = rs.getClass().getInterfaces();<br /> (tng) (tng)if(interfaces==null||interfaces.length==0){<br /> (tng) (tng) (tng)interfaces = new Class[1];<br /> (tng) (tng) (tng)interfaces[0] = ResultSet.class; (tng) (tng)<br /> (tng) (tng)}<br /> (tng)<br /> (tng) (tng)ResultSet rs2 = (ResultSet)Proxy.newProxyInstance(rs.getClass().getClassLoader(),interfaces,this);<br /> (tng) (tng)return rs2;<br /> (tng)<br /> (tng)}<br /><br /> (tng)/** (tng) <br /> (tng) * l果getStringҎ(gu) (tng) <br /> (tng) */<br /> (tng)public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { (tng)<br /> (tng) (tng)String method = m.getName();<br /> (tng) (tng)if(decode && GETSTRING.equals(method)){<br /> (tng) (tng) (tng)try{<br /> (tng) (tng) (tng) (tng)String result = (String)m.invoke(rs,args);<br /> (tng) (tng) (tng) (tng)if(result!=null) (tng) (tng) (tng) (tng) (tng)<br /> (tng) (tng) (tng) (tng) (tng)return new String(result.getBytes("8859_1"));<br /> (tng) (tng) (tng) (tng)return null;<br /> (tng) (tng) (tng)<br /> (tng) (tng) (tng)}catch(InvocationTargetException e){<br /> (tng) (tng) (tng) (tng)throw e.getTargetException();<br /> (tng) (tng) (tng) (tng)}<br /> (tng) (tng) (tng)<br /> (tng) (tng)} (tng)<br /> (tng) (tng)<br /> (tng) (tng)try{<br /> (tng) (tng) (tng)return m.invoke(rs, args);<br /> (tng) (tng)}catch(InvocationTargetException e){<br /> (tng) (tng) (tng)throw e.getTargetException();<br /> (tng) (tng)}<br /> (tng)}<br /> (tng)<br /> (tng)private final static String GETSTRING = "getString";<br /><br />}</p> <p>  现在我们已经把三个接口的代理cd好了(jin)Q下一步就是怎么来用这三个cR其实对于用者来讲ƈ不需要关?j)三个类Q只需要了(jin)解_Connection可以了(jin)Q因为另外两个是_Connection直接调用的。ؓ(f)?jin)用_Connection我们必须传入两个参数Q第一个是数据库实际的数据库连接实例,另外一个是布尔g表是否进行{码处理。我们必d通过实际的情况获取到数据库连接后再传入_Connection的构造函C为参敎ͼ下面例子告诉你如何来使用_Connectionq个c:(x)</p> <p style="BACKGROUND: #eeeeee">  Connection conn = getConnection(); //获取数据库连?br />  boolean coding = false; //从配|或者其他地方读取是否进行{码的配置 (tng)<br />  //接管数据库连接实例?br />  _Connection _conn = new _Connection(conn,coding);<br />  //获得接管后的数据库连接实例,以后直接使用conn2而不是conn (tng)<br />  Connection conn2 = _conn.getConnection();</p> <p>  因ؓ(f)对一个应用系l来Ԍ数据库连接的获取必然有统一的方法,在这个方法中加入对连接的接管可以一x逸的解决数据库的~码问题?/p> <p>  <strong>性能比较</strong></p> <p>  功能没有问题?jin),开发者接下来׃(x)兛_(j)性能的问题,因ؓ(f)在进行一些对响应速度要求很高或者大数据量的处理情况下性能成Z个非常突出的问题。由于JAVA中的动态接口代理采用的是反(ReflectionQ机Ӟ同时又加入我们自q一些代码例如方法名判断Q字W串转码{操作因此在性能上肯定比不上直接使用没有l过接管的数据库q接。但是这Ҏ(gu)能上的差别是不是我们可以忍受的呢,为此我做?jin)一个试验对二者进行了(jin)比较Q?/p> <p>  试环境单描qͼ(x)</p> <p>  使用ACCESS数据库,Z张结构一L(fng)表,计算从获取连接后到插入数据完毕后的时间差Q两个程序(直连数据库和使用q接接管Q都q行的字W串的{码操作?/p> <p>  试l果Q?/p> <table cellspacing="1" cellpadding="1" width="500" align="center" bgcolor="#999999" border="0"> <tbody> <tr bgcolor="#ffffff"> <td align="middle" height="25">插入记录?/td> <td align="middle">直连数据库程序耗时 单位Qms</td> <td align="middle">使用q接接管E序耗时</td> <td align="middle">性能比较</td> </tr> <tr bgcolor="#ffffff"> <td height="25">1000</td> <td>2063</td> <td>2250</td> <td>9.0%</td> </tr> <tr bgcolor="#ffffff"> <td height="25">5000</td> <td>8594</td> <td>8359</td> <td>-2.7%</td> </tr> <tr bgcolor="#ffffff"> <td height="25">10000</td> <td>16750</td> <td>17219</td> <td>2.8%</td> </tr> <tr bgcolor="#ffffff"> <td height="25">15000</td> <td>22187</td> <td>23000</td> <td>3.6%</td> </tr> <tr bgcolor="#ffffff"> <td height="25">20000</td> <td>27031</td> <td>27813</td> <td>2.9%</td> </tr> </tbody> </table> <p>  从上面这张测试结果表中来看,二者的性能的差别非常小Q尽在两万条数据的扚w插入的时候时间差别也不会(x)多于一U钟Q这L(fng)l果应该说还是o(h)人满意的Q毕竟ؓ(f)?jin)程序良好的l构有时候牺牲一点点性能q是值得的?/p> <p>  本文是我之前文章《用JAVA动态代理实现数据库q接池》中提出的数据库q接池实现的q一步完善,同样使用动态接口代理的技术来解决数据库编码的问题。JAVA的这个高U技术可以用来解册多实际中非常手的问题,像本文提到的编码问题的处理以及(qing)数据库连接池的实玎ͼ同时在WEB开发框架的实现上也有非常大的作为。欢q对q方面感兴趣的朋友来信共同来研究?br /><br />from: <a >http://www.javafan.net/article/20041212111952983.html</a></p> <img src ="http://m.tkk7.com/weidagang2046/aggbug/85178.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/weidagang2046/" target="_blank">weidagang2046</a> 2006-12-03 13:22 <a href="http://m.tkk7.com/weidagang2046/articles/85178.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBC性能优化技?/title><link>http://m.tkk7.com/weidagang2046/articles/84051.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Tue, 28 Nov 2006 06:59:00 GMT</pubDate><guid>http://m.tkk7.com/weidagang2046/articles/84051.html</guid><wfw:comment>http://m.tkk7.com/weidagang2046/comments/84051.html</wfw:comment><comments>http://m.tkk7.com/weidagang2046/articles/84051.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/weidagang2046/comments/commentRss/84051.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/weidagang2046/services/trackbacks/84051.html</trackback:ping><description><![CDATA[ (tng) <p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如果可能Q避免访问数据库</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-bidi-font-weight: bold">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">为应用选择最好最快的 JDBC </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">驱动 ,参?a ><font color="#0000ff">本站文章</font></a> ?JDBC3.0</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">提供?jin)新的特性来提高性能Q诸如连接池Q?statemente池的改进</span><b><span lang="EN-US"><o:p>  (tng) </o:p></span></b></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-bidi-font-weight: bold">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)</span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">Ҏ(gu)据库使用q接池ƈ且重用连接,而不要重复打开和关闭连接。最佳的q接池大是当连接池大到_使服务请求不{待</span><b><span lang="EN-US"><o:p></o:p></span></b></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">量使用支持 JDBC3.0 的驱动,因ؓ(f) JDBC3.0 支持包括 DataSource 对象Q连接池Q分布式事务支持Q?RowSets ?prepared statement 池等性能增强Ҏ(gu)?/span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">Prepared statement 池(自从 JDBC3.0 开始有Q高速缓存已l预先优化ƈq行?jin)?SQL 查询Q这P他们被再ơ请求的时候,不必l历再次的优化预处理Q避免最优化步骤Q诸如检查语法,验证地址Q优化访问\径和执行计划Q?Statement 池是一个很好的Q重要的性能优化Ҏ(gu)</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-list: l172 level1 lfo14; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">JDBC3.0 中的 Statement 池和q接池能合作׃n statement 池,q样Q能使用一个已高速缓存的 statement Q该 statement 来自另外一个连接)(j)的连接,在由Mq接执行?一些SQL 首次被执行时Q生的 statement 准备开销仅一?/span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">RowSet对象?ResultSet 对象怼Q但是能提供当断开q接的时候对数据库数据的讉K。这允许数据以它最单的形式被高效的高速缓?/span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-list: l172 level1 lfo14; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用同一个连接执行多?statements</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">关闭 autocommit Q但不要让事务打开太久</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">避免事务分布开Q事务跨多个连接)(j)</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">最化数据库的行和列数据获取。?setMaxRows, setMaxFieldSize,</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">?SetFetchSize</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-bidi-font-weight: bold">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">使用最高效的数据类型:(x)字符串比整数型快Q整数型比Q点类型和旉戳类型都要高效(是否不太理解^&^Q这是针对DB2数据库处理来说的Q处理charactercd最快,而处理integercd通常需要一些{换或者字节排序)(j)</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">使用 updateXXX()</span>Ҏ(gu)<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">更新Q?updateXXX() 在可更新的结果集上调用。结果集已经定位C(jin)一?, 因此当用一?UPDATE statement Ӟ可以消除通常的查找要更新的数据行的开销</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">CacheMh的元数据Q?metadata Qƈ可能少的用元数据 Ҏ(gu)Q其慢的E度一用便?/span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">避免在元数据 查询中?null 参数</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">使用虚拟查询获得一行的元数据,不要使用getcolumns()Q假如应用允许用户用列数据Q应用是使用getColumns来返回列的信息给用户q是准备一个虚拟查询而后调用getMetadata呢?</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">使用存储q程Q避免多余的|络传输</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在存储过E中使用参量Q不要将数据挨个地放在statement中,最化解析开销。此条针对DB2来说Q其它数据库未必适用。SQLL以字W串形式发送给DB2数据库,例如Q?/span><br /><font color="#ff0000">CallableStatement cstmt = conn.prepareCall ("call getCustName (12345)");<br />ResultSet rs = cstmt.executeQuery ();</font><br />DB2服务器必解析该SQLQ验证参量类型,q将参量转化为正的数据cd?/p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">寚w要重复执行的statement使用预处理statementQPreparedStatementQ?/span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">选择使用最x标:(x)对连l读取用游标;对双向滚动用游标。对仅返回一行的查询避免使用游标?/span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在JVM中Cache频繁h的数据,避免不必要的数据库请?/span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">采用预读取机Ӟ 扚w取行Q而不要一ơ一?。调整批大小和预取行的数量。避免用预?BLOB 数据?/span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">除非l对需要,否则避免Ud数据</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在数据穿q网l之前要使流化数据( Streamline data Q?/span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">避免每次处理一行,可能一起处理多行?/span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在表中统计个敎ͼ例如Q?select count(*) from myTable,yourTable where ?/span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">Q属于资源密集型的。试试首先选入临时表,仅返回该计数QcountQ,然后发送精的二次查询获得临时表中的行的子集?/span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">?/span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">当的使用 SQL 能减资源请求。用返回所需数据的最值的查询Q避?select * 查询。一个返回小的数据子集的复杂查询Q比一个简单的Q返回超q所需的大量数据的单查询更高效?/span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">使你的查询尽可能_yQ例如:(x)可能精地最化要传输的数据Q其是所需的子?/span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">努力扚w更新Q将 statement 攉CP然后在一个事务里面一h行。如果可能,使用有条件的逻辑和(f)时变量来辑ֈ statement 批处?/span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">永远不要?DBMS 事务跨越用户输入</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">考虑使用乐观锁。乐观锁使用旉戳验证数据是否还没有被其他用h变,否则事务p|</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">使用 恰当的更斎ͼ例如Q更新行</span>/<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">表中已经存在的数据,而不要添加或者删除行</span>/<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">表。在适当的位|更新数据要比移动数据快得多Q如果更新需要的I间比表设计能提供的更多Q这可能是需要的。如果你设计的行需要空间初始化Q更新将?x)更快。交易是你的表可能需要更多的盘I间Q但可能速度更快。由于磁盘空间是便宜的,使用一点点能提高性能</span>Q这应该说是非常有h(hun)值的投资</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">分开存储正在操作的数据和历史数据Q更一般的情况是将频繁使用的数据和不常使用的数据分开存储Q?/span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">可能小的保留你的操作数据集Q避免必读那些不相关的数据</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">DBMS可以很好的ƈ行运转,量应用设计成当和 DBMS交互时应用能做其他事情?/span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">使用水U操作和q行操作?应用设计成支持大量q行q程Q?使应用运行更快。如果要处理多步Q努力设计好应用Q以使后来的步骤能够在Q何优先的q程已经完成的数据部分上开始工作,而不是必ȝC先进E完?/span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng)</span></span> (tng)<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">事物的保护别越高,性能损失p大。事物别按增长的顺序ؓ(f)Q?TRANSACTION_NONE, TRANSACTION_READ_UNCOMMITTED, TRANSACTION_READ_COMMITTED, TRANSACTION_REPEATABLE_READ, TRANSACTION_SERIALIZABLE。用Connection.setTransactionIsolation() 讄你想要的事物U别</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng)</span></span><span lang="EN-US" style="FONT-WEIGHT: normal; FONT-SIZE: 7pt; FONT-STYLE: normal; FONT-FAMILY: Wingdings; FONT-VARIANT: normal"></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">默认的自动提交模式由于每一个数据库命o(h)都成Z个单独的事务Q这?x)严重?jing)响性能Q关闭自动提交(Connection.setAutoCommit(false) Q,明确声明事务</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">通过整合多个事务Z个的扚w操作Qƈ在一个statement中用Statement.addBatch() 和Statement.executeBatch()</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) </span></span><span style="FONT: 7pt 'Times New Roman'"> (tng)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman"> Savepoints (from JDBC3.0)需要昂늚资源。一旦不再需要,qM用Connection.releaseSavepoint()释放掉Savepoints</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">ConnectionPoolDataSource (from JDBC3.0)和PooledConnection接口接池提供?jin)built-in支持</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT: 7pt 'Times New Roman'"> (tng) </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">使用setLogWriter() (from Driver, DataSource, or ConnectionPooledDataSource; from JDBC3.0) 帮助跟踪JDBC?/span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT: 7pt 'Times New Roman'"> (tng) </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">使用Connection.setReadOnly(true)优化只读数据库(操作Q交?/span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span lang="EN-US"></span><span style="FONT: 7pt 'Times New Roman'"> (tng) <span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">使用Connection.nativeSQL()察看SQL查询如何在数据库U执行,帮助保SQL已被优化</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT: 7pt 'Times New Roman'"> (tng)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">切记Q一旦可能,立刻关闭Statement和ResultSet</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT: 7pt 'Times New Roman'"> (tng)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">使用DatabaseMetaData获得数据库功能性信?/span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT: 7pt 'Times New Roman'"> (tng)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">一直捕捉和处理数据库警告和异常</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT: 7pt 'Times New Roman'"> (tng)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">使用最恰当的数据类型明数据的cdQ例如:(x)以datecd存储日期Q儿不要用varchar</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'"> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) </span></span><span style="FONT: 7pt 'Times New Roman'"> (tng)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">使用可滚动ResultSet (JDBC 2.0)<br /><br />from: <a >http://www.ijsp.net/2/2003-9/20/0000431.shtml</a></span></p><img src ="http://m.tkk7.com/weidagang2046/aggbug/84051.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/weidagang2046/" target="_blank">weidagang2046</a> 2006-11-28 14:59 <a href="http://m.tkk7.com/weidagang2046/articles/84051.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>我怎样创徏一个序列号或是自动递增的字D?http://m.tkk7.com/weidagang2046/articles/83633.htmlweidagang2046weidagang2046Sun, 26 Nov 2006 09:06:00 GMThttp://m.tkk7.com/weidagang2046/articles/83633.htmlhttp://m.tkk7.com/weidagang2046/comments/83633.htmlhttp://m.tkk7.com/weidagang2046/articles/83633.html#Feedback0http://m.tkk7.com/weidagang2046/comments/commentRss/83633.htmlhttp://m.tkk7.com/weidagang2046/services/trackbacks/83633.htmlPostgreSQL 支持 SERIAL 数据cd。(字段定义为SERIAL后)(j)自动创Z个序列生成器Q例如:(x)

   CREATE TABLE person ( 
      id   SERIAL, 
      name TEXT 
   );

?x)自动{换ؓ(f)以下SQL语句Q?

   CREATE SEQUENCE person_id_seq;
   CREATE TABLE person ( 
      id   INT4 NOT NULL DEFAULT nextval('person_id_seq'),
      name TEXT
   );

from: http://www.pgsqldb.org/twiki/bin/view/PgSQL/PostgreFAQ#4.11.1


weidagang2046 2006-11-26 17:06 发表评论
]]>
攑ּ ORM 改用 SqlMap ?N 个理?/title><link>http://m.tkk7.com/weidagang2046/articles/83620.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Sun, 26 Nov 2006 08:02:00 GMT</pubDate><guid>http://m.tkk7.com/weidagang2046/articles/83620.html</guid><wfw:comment>http://m.tkk7.com/weidagang2046/comments/83620.html</wfw:comment><comments>http://m.tkk7.com/weidagang2046/articles/83620.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/weidagang2046/comments/commentRss/83620.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/weidagang2046/services/trackbacks/83620.html</trackback:ping><description><![CDATA[ <p>1. 在项目中l常到的数据库分页查询, ORM 一般都支持的不? 如果?ORM, q部分程序往往要自己扩? ?SqlMap 对各U查询语句不分彼? 一概在 Map 文g里定义?/p> <p>2. 对一些稍微复杂些的语? 例如在对金额{敏感数据操作时, 一个常用的操作序列?<br />a. 先取出当前金?br />b. q算后得到更新的金额<br />c. 执行 Update 语句: Update < tableName > set amount= < New amount > where amount= < Old amount > <br />q种操作?ORM 不能支持? SqlMap 能很好的支持?/p> <p>3. SqlMap ?Domain 对象可以直接攑֜业务? 一?ORM 的对数据讉K的基c要攑֜数据讉K?因ؓ(f)带有Ҏ(gu)据访问的接口, 攑֜业务层不合?, 增加?jin)代码的冗余度?/p> <p>4. ?ORM 的目的是什? 最主要的目的是减少重复的底层编E工作量, SqlMap 完全可以做到?/p> <p>再说?SqlMap 的不?</p> <p>1. 因ؓ(f)不象 ORM 那样生成E_可靠的对数据讉K的基c? 所以要?Map 操作做好充的单元测? 增加?jin)测试的工作量?/p> <p>2. 每次改动数据? Map ?Domain 文g往往要手工修? 因ؓ(f) SqlMap 的灵zL? 往往我们?x)手工调?Map 而不?x)直接?Generator 生成的代码?br /><br />from: <a >http://matrix.foresee.cn/blogs/simon/archives/001638.html</a></p> <img src ="http://m.tkk7.com/weidagang2046/aggbug/83620.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/weidagang2046/" target="_blank">weidagang2046</a> 2006-11-26 16:02 <a href="http://m.tkk7.com/weidagang2046/articles/83620.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>量数据库的查询优化?qing)分늮法方?/title><link>http://m.tkk7.com/weidagang2046/articles/77597.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Fri, 27 Oct 2006 04:17:00 GMT</pubDate><guid>http://m.tkk7.com/weidagang2046/articles/77597.html</guid><wfw:comment>http://m.tkk7.com/weidagang2046/comments/77597.html</wfw:comment><comments>http://m.tkk7.com/weidagang2046/articles/77597.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/weidagang2046/comments/commentRss/77597.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/weidagang2046/services/trackbacks/77597.html</trackback:ping><description><![CDATA[在以下的文章中,我将以“办公自动化”系lؓ(f)例,探讨如何在有着1000万条数据的MS SQL SERVER数据库中实现快速的数据提取和数据分c(din)以下代码说明了(jin)我们实例中数据库的“红头文件”一表的部分数据l构Q? <p>CREATE TABLE [dbo].[TGongwen] ( (tng) (tng) (tng) --TGongwen是红头文件表?/p><p> (tng) (tng) [Gid] [int] IDENTITY (1, 1) NOT NULL ,<br />--本表的idP也是主键</p><p> (tng) (tng) [title] [varchar] (80) COLLATE Chinese_PRC_CI_AS NULL , (tng) <br />--U头文g的标?/p><p> (tng) (tng) [fariqi] [datetime] NULL ,<br />--发布日期</p><p> (tng) (tng) [neibuYonghu] [varchar] (70) COLLATE Chinese_PRC_CI_AS NULL ,<br />--发布用户</p><p> (tng) (tng) [reader] [varchar] (900) COLLATE Chinese_PRC_CI_AS NULL ,</p><p>--需要浏览的用户。每个用户中间用分隔W?”分开</p><p>) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]</p><p>GO</p><p><br />  下面Q我们来往数据库中d1000万条数据Q?/p><p>declare @i int</p><p>set @i=1</p><p>while @i<=250000</p><p>begin</p><p> (tng) (tng) (tng) insert into Tgongwen(fariqi,neibuyonghu,reader,title) values('2004-2-5','通信U?,'通信U?办公?王局?刘局?张局?admin,刑侦支队,特勤支队,交E警支?l侦支队,hU?d支队,外事U?,'q是最先的25万条记录')</p><p> (tng) (tng) (tng) set @i=@i+1</p><p>end</p><p>GO</p><p> (tng)</p><p>declare @i int</p><p>set @i=1</p><p>while @i<=250000</p><p>begin</p><p> (tng) (tng) (tng) insert into Tgongwen(fariqi,neibuyonghu,reader,title) values('2004-9-16','办公?,'办公?通信U?王局?刘局?张局?admin,刑侦支队,特勤支队,交E警支?l侦支队,hU?外事U?,'q是中间?5万条记录')</p><p> (tng) (tng) (tng) set @i=@i+1</p><p>end</p><p>GO</p><p> (tng)</p><p>declare @h int</p><p>set @h=1</p><p>while @h<=100</p><p>begin</p><p>declare @i int</p><p>set @i=2002</p><p>while @i<=2003</p><p>begin</p><p>declare @j int</p><p> (tng) (tng) (tng) (tng) (tng) (tng) (tng) set @j=0</p><p> (tng) (tng) (tng) (tng) (tng) (tng) (tng) while @j<50</p><p> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) begin</p><p>declare @k int</p><p> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) set @k=0</p><p> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) while @k<50</p><p> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) begin</p><p> (tng) (tng) (tng) insert into Tgongwen(fariqi,neibuyonghu,reader,title) values(cast(@i as varchar(4))+'-8-15 3:'+cast(@j as varchar(2))+':'+cast(@j as varchar(2)),'通信U?,'办公?通信U?王局?刘局?张局?admin,刑侦支队,特勤支队,交E警支?l侦支队,hU?外事U?,'q是最后的50万条记录')</p><p> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) set @k=@k+1</p><p> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) end</p><p>set @j=@j+1</p><p> (tng) (tng) (tng) (tng) (tng) (tng) (tng) end</p><p>set @i=@i+1</p><p>end</p><p>set @h=@h+1</p><p>end</p><p>GO</p><p> (tng)</p><p>declare @i int</p><p>set @i=1</p><p>while @i<=9000000</p><p>begin</p><p> (tng) (tng) (tng) insert into Tgongwen(fariqi,neibuyonghu,reader,title) values('2004-5-5','通信U?,'通信U?办公?王局?刘局?张局?admin,刑侦支队,特勤支队,交E警支?l侦支队,hU?d支队,外事U?,'q是最后添加的900万条记录')</p><p> (tng) (tng) (tng) set @i=@i+1000000</p><p>end</p><p>GO</p><p>  通过以上语句Q我们创Z(jin)25万条由通信U于2004q??日发布的记录Q?5万条由办公室?004q??日发布的记录Q?002q和2003q各100?500条相同日期、不同分U的由通信U发布的记录Q共50万条Q,q有由通信U于2004q??日发布的900万条记录Q合?000万条?br /><br />from: <a >http://www.pconline.com.cn/pcedu/empolder/db/sql/0501/538958.html</a></p><img src ="http://m.tkk7.com/weidagang2046/aggbug/77597.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/weidagang2046/" target="_blank">weidagang2046</a> 2006-10-27 12:17 <a href="http://m.tkk7.com/weidagang2046/articles/77597.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQL查询的分|\http://m.tkk7.com/weidagang2046/articles/77598.htmlweidagang2046weidagang2046Fri, 27 Oct 2006 04:17:00 GMThttp://m.tkk7.com/weidagang2046/articles/77598.htmlhttp://m.tkk7.com/weidagang2046/comments/77598.htmlhttp://m.tkk7.com/weidagang2046/articles/77598.html#Feedback0http://m.tkk7.com/weidagang2046/comments/commentRss/77598.htmlhttp://m.tkk7.com/weidagang2046/services/trackbacks/77598.html其实我们可以只取出我们每需要显C的记录?q样的速度是惊人的,非常?q里我们?x)用到聚集?ch)引来快速确定我们需要取出的记录数的位置.如下?
if p>1 then 'p为PAGE|
if n="next" then'下一?br />sql="select top 26 * from song1 where id > "&pk&" and contains(songtitle,'"&songname&"')" 'PK为当前页的最大ID?br />elseif n="prev" then'上一?br />sql="select top 26 * from song1 where id < "&previd&" and contains(songtitle,'"&songname&"') order by id desc"'previd最ID
end if
else
sql="select top 26 * from song1 where contains(songtitle,'"&songname&"')"'没有指定PAGE?默认W一?br />end if
q里用到?jin)全文检?速度也是很快?我在52万记录下试,最快可?6MS(机器C1.7. DDR 256M),感觉比较可以,我用like代码模糊查询|试过,在结果集很多的情况下比全文更?但是如果l果很少(整个表只有那么几?是漫长的过E?因ؓ(f)要对全表q行扫描!

按上面的Ҏ(gu)不能得出所查询l果得总记录数,q里我们可以用select count(*) 来获取记录L,速度还q得?不过感觉要慢一?特别是记录集很多得情?不过q样占用得内存很得.
以上是我最q搞SQL查询得心(j)?

from: http://www.fixdown.com/article/article/2121.htm



weidagang2046 2006-10-27 12:17 发表评论
]]>
SQL Server 存储q程的分?/title><link>http://m.tkk7.com/weidagang2046/articles/77596.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Fri, 27 Oct 2006 04:16:00 GMT</pubDate><guid>http://m.tkk7.com/weidagang2046/articles/77596.html</guid><wfw:comment>http://m.tkk7.com/weidagang2046/comments/77596.html</wfw:comment><comments>http://m.tkk7.com/weidagang2046/articles/77596.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/weidagang2046/comments/commentRss/77596.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/weidagang2046/services/trackbacks/77596.html</trackback:ping><description><![CDATA[ <p> <font color="#004fc6"> <font color="#000000">  建立表:(x) <br /><br />CREATE TABLE [TestTable] ( <br />[ID] [int] IDENTITY (1, 1) NOT NULL , <br />[FirstName] [nvarchar] (100) COLLATE Chinese_PRC_CI_AS NULL , <br />[LastName] [nvarchar] (100) COLLATE Chinese_PRC_CI_AS NULL , <br />[Country] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL , <br />[Note] [nvarchar] (2000) COLLATE Chinese_PRC_CI_AS NULL <br />) ON [PRIMARY] <br />GO <br /><br /><br /><br />插入数据Q?2万条Q用更多的数据测试会(x)明显一? <br />SET IDENTITY_INSERT TestTable ON <br /><br />declare @i int <br />set @i=1 <br />while @i<=20000 <br />begin <br />insert into TestTable([id], FirstName, LastName, Country,Note) values(@i, ''FirstName_XXX'',''LastName_XXX'',''Country_XXX'',''Note_XXX'') <br />set @i=@i+1 <br />end <br /><br />SET IDENTITY_INSERT TestTable OFF <br /><br /><br /><br />------------------------------------- <br /><br />分页Ҏ(gu)一Q?利用Not In和SELECT TOP分页) <br />语句形式Q?<br />SELECT TOP 10 * <br />FROM TestTable <br />WHERE (ID NOT IN <br />(SELECT TOP 20 id <br />FROM TestTable <br />ORDER BY id)) <br />ORDER BY ID <br /><br /><br />SELECT TOP 大?* <br />FROM TestTable <br />WHERE (ID NOT IN <br />(SELECT TOP 大?| id <br />FROM ?<br />ORDER BY id)) <br />ORDER BY ID <br /><br />------------------------------------- <br /><br />分页Ҏ(gu)二:(x)(利用ID大于多少和SELECT TOP分页Q?<br />语句形式Q?<br />SELECT TOP 10 * <br />FROM TestTable <br />WHERE (ID > <br />(SELECT MAX(id) <br />FROM (SELECT TOP 20 id <br />FROM TestTable <br />ORDER BY id) AS T)) <br />ORDER BY ID <br /><br /><br />SELECT TOP 大?* <br />FROM TestTable <br />WHERE (ID > <br />(SELECT MAX(id) <br />FROM (SELECT TOP 大?| id <br />FROM ?<br />ORDER BY id) AS T)) <br />ORDER BY ID <br /><br /><br />------------------------------------- <br /><br />分页Ҏ(gu)三:(x)(利用SQL的游标存储过E分? <br />create procedure XiaoZhengGe <br />@sqlstr nvarchar(4000), --查询字符?<br />@currentpage int, --WN?<br />@pagesize int --每页行数 <br />as <br />set nocount on <br />declare @P1 int, --P1是游标的id <br />@rowcount int <br />exec sp_cursoropen @P1 output,@sqlstr,@scrollopt=1,@ccopt=1,@rowcount=@rowcount output <br />select ceiling(1.0*@rowcount/@pagesize) as 总页?-,@rowcount as 总行?@currentpage as 当前?<br />set @currentpage=(@currentpage-1)*@pagesize+1 <br />exec sp_cursorfetch @P1,16,@currentpage,@pagesize <br />exec sp_cursorclose @P1 <br />set nocount off <br /><br />其它的方案:(x)如果没有主键Q可以用临时表,也可以用Ҏ(gu)三做Q但是效率会(x)低?<br />优化的时候,加上主键和烦(ch)引,查询效率?x)提高?<br /><br />通过SQL 查询分析器,昄比较Q我的结论是: <br />分页Ҏ(gu)二:(x)(利用ID大于多少和SELECT TOP分页Q效率最高,需要拼接SQL语句 <br />分页Ҏ(gu)一Q?利用Not In和SELECT TOP分页) 效率ơ之Q需要拼接SQL语句 <br />分页Ҏ(gu)三:(x)(利用SQL的游标存储过E分? 效率最差,但是最为通用 <br /><br />在实际情况中Q要具体分析。?/font> <strong> <img height="1" src="http://cfan.net.cn/down_info.asp?id=15547" width="1" border="0" /> <br /> <br />from: <a >http://cfan.net.cn/info/15547.html</a></strong> </font> </p> <img src ="http://m.tkk7.com/weidagang2046/aggbug/77596.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/weidagang2046/" target="_blank">weidagang2046</a> 2006-10-27 12:16 <a href="http://m.tkk7.com/weidagang2046/articles/77596.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>存储q程从入门到熟练(多个存储q程完整实例?qing)调用方?http://m.tkk7.com/weidagang2046/articles/77595.htmlweidagang2046weidagang2046Fri, 27 Oct 2006 04:14:00 GMThttp://m.tkk7.com/weidagang2046/articles/77595.htmlhttp://m.tkk7.com/weidagang2046/comments/77595.htmlhttp://m.tkk7.com/weidagang2046/articles/77595.html#Feedback0http://m.tkk7.com/weidagang2046/comments/commentRss/77595.htmlhttp://m.tkk7.com/weidagang2046/services/trackbacks/77595.html (tng)

①ؓ(f)什么要使用存储q程?
因ؓ(f)它比SQL语句执行?

②存储过E是什?
把一堆SQL语句|在一?q可以根据条件执行不同SQL语句.(AX写作本文时观?

③来一个最单的存储q程
CREATE PROCEDURE dbo.testProcedure_AX
AS
select userID from USERS order by userid desc

?dbo.testProcedure_AX是你创徏的存储过E名,可以改ؓ(f):AXzhz{?别跟关键字冲H就行了(jin).AS下面是一条SQL语句,不会(x)写SQL语句的请回避.

④我怎么在ASP.NET中调用这个存储过E?
下面黄底的这两行够使了(jin).
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) public static string GetCustomerCName(ref ArrayList arrayCName,ref ArrayList arrayID)
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) SqlConnection con=ADConnection.createConnection();
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) SqlCommand cmd=new SqlCommand("testProcedure_AX",con);
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cmd.CommandType=CommandType.StoredProcedure;
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) con.Open();
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) try
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) SqlDataReader dr=cmd.ExecuteReader();
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) while(dr.Read())
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) if(dr[0].ToString()=="")
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) arrayCName.Add(dr[1].ToString());
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) con.Close();
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) return "OK!";
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) catch(Exception ex)
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) con.Close();
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) return ex.ToString();
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
?其实是把以?br />SqlCommand cmd=new SqlCommand("select userID from USERS order by userid desc",con);
中的SQL语句替换为存储过E名,再把cmd的类型标注ؓ(f)CommandType.StoredProcedure(存储q程)

⑤写个带参数的存储过E吧,上面q个单得有点惨不忍睹,不过q是蛮实用的.
参数带就带两,一个的没面?太小家子气了(jin).

CREATE PROCEDURE dbo.AXzhz
/*
q里写注?br />*/
@startDate varchar(16),
@endDate varchar(16)
AS
 (tng)select id (tng) from table_AX where commentDateTime>@startDate and commentDateTime<@endDate order by contentownerid DESC

?@startDate varchar(16)是声明@startDate q个变量,多个变量名间用?】隔开.后面的SQL可以用这个变量了(jin).

⑥我怎么在ASP.NET中调用这个带参数的存储过E?

 (tng)public static string GetCustomerCNameCount(string startDate,string endDate,ref DataSet ds)
{
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) SqlConnection con=ADConnection.createConnection();
//-----------------------注意q一D?-------------------------------------------------------------------------------------------------------
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) SqlDataAdapter da=new SqlDataAdapter("AXzhz",con);

 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) para0=new SqlParameter("@startDate",startDate);
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) para1=new SqlParameter("@endDate",endDate);
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) da.SelectCommand.Parameters.Add(para0);
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) da.SelectCommand.Parameters.Add(para1);
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) da.SelectCommand.CommandType=CommandType.StoredProcedure;
//-------------------------------------------------------------------------------------------------------------------------------


 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) try
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) con.Open();
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) da.Fill(ds);
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) con.Close();
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) return "OK";
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) catch(Exception ex)
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) return ex.ToString();
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) } (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) }

?把命令的参数dq去,O(jin)K?br />鸟的,改字体颜色的东西太垃圾了(jin),改不?大家凑活着?

⑦我q想看看SQL命o(h)执行成功?jin)没?
注意看下面三行红色的语句

CREATE PROCEDURE dbo.AXzhz
/*
 (tng) @parameter1 用户?br /> (tng) @parameter2 新密?br />*/
@password nvarchar(20),
@userName nvarchar(20)
AS
declare @err0 int
update WL_user set password=@password where UserName=@userName
set @err0=@@error
select (tng) @err0 as err0

?先声明一个整型变量@err0,再给其赋gؓ(f)@@error(q个是系l自动给出的语句是否执行成功,0为成?其它为失?,最后通过select把它选择出来,某位高h说可以通过Returnq回,出本h的认知范?俺暂时不?以后再补充吧

⑧那怎么从后台获得这个执行成功与否的值呢?
下面q段代码可以告诉你答?
 (tng) (tng) (tng) public static string GetCustomerCName()
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) SqlConnection con=ADConnection.createConnection();
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) SqlCommand cmd=new SqlCommand("AXzhz",con);
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cmd.CommandType=CommandType.StoredProcedure;
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) para0=new SqlParameter("@startDate","2006-9-10");
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) para1=new SqlParameter("@endDate","2006-9-20");
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) da.SelectCommand.Parameters.Add(para0);
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) da.SelectCommand.Parameters.Add(para1);
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) con.Open();
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) try
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Int32 re=(int32)cmd.ExecuteScalar();
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) con.Close();
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) if (re==0)
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) return "OK!";
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) else
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) return "false";
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) catch(Exception ex)
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) con.Close();
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) return ex.ToString();
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
?是通过SqlCommand的ExecuteScalar()Ҏ(gu)取回q个?q句话是从MSDN上找?为改?
 (tng) (tng) (tng) (tng) int re=(int)cmd.ExecuteScalar(); (tng) 99%正确,现在没时间验?期待(zhn)的试!!!

⑨我要根据传入的参数判断执行哪条SQL语句!!~
下面q个存储q程可以满我们的要?竟然是Pascal/VB的写?Begin----End ,不是{},,,对用C#的我来说,q个语法有点恶心(j).........

ALTER PROCEDURE dbo.selectCustomerCNameCount
@customerID int
AS
if @customerID=-1
 (tng)begin
 (tng)select contentownerid ,userCName,count(*) as countAll from view_usercomment group by contentownerid,userCName order by contentownerid DESC
 (tng)end
else
 (tng)begin
 (tng)select contentownerid ,userCName,count(*) as countAll from view_usercomment where contentownerid=@customerID group by contentownerid,userCName order by contentownerid DESC
 (tng)end

好了(jin),俺的水^只止于此,也够菜鸟们喝一壶的?q有更多东西{着我们d?无尽的征?!!!!!!!!!!

from: http://www.knowsky.com/340678.html



weidagang2046 2006-10-27 12:14 发表评论
]]>
数据库烦(ch)引应?ms-sql)http://m.tkk7.com/weidagang2046/articles/77594.htmlweidagang2046weidagang2046Fri, 27 Oct 2006 04:13:00 GMThttp://m.tkk7.com/weidagang2046/articles/77594.htmlhttp://m.tkk7.com/weidagang2046/comments/77594.htmlhttp://m.tkk7.com/weidagang2046/articles/77594.html#Feedback0http://m.tkk7.com/weidagang2046/comments/commentRss/77594.htmlhttp://m.tkk7.com/weidagang2046/services/trackbacks/77594.html (tng)

一、烦(ch)引的概念
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) 索引是加快(g)索表中数据的Ҏ(gu)?a >数据?/a>的烦(ch)引类g书籍的烦(ch)引。在书籍中,索引允许用户不必阅完整个书pq速地扑ֈ所需要的信息。在数据库中Q烦(ch)引也允许数据库程序迅速地扑ֈ表中的数据,而不必扫描整个数据库?/p>

二、烦(ch)引的特点
 (tng) (tng) (tng) 1.索引可以加快数据库的(g)索速度
 (tng) (tng) (tng) 2.索引降低?jin)数据库插入、修攏V删除等l护d的速度
 (tng) (tng) (tng) 3.索引创徏在表上,不能创徏在视图上
 (tng) (tng) (tng) 4.索引既可以直接创建,也可以间接创?
 (tng) (tng) (tng) 5.可以在优化隐藏中Q用烦(ch)?
 (tng) (tng) (tng) 6.使用查询处理器执行SQL语句Q在一个表上,一ơ只能用一个烦(ch)?
 (tng) (tng) (tng) 7.其他

三、烦(ch)引的优点
 (tng) (tng) (tng) 1.创徏唯一性烦(ch)引,保证数据库表中每一行数据的唯一?br /> (tng) (tng) (tng) 2.大大加快数据的检索速度Q这也是创徏索引的最主要的原?br /> (tng) (tng) (tng) 3.加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义?br /> (tng) (tng) (tng) 4.在用分l和排序子句q行数据(g)索时Q同样可以显著减查询中分组和排序的旉?br /> (tng) (tng) (tng) 5.通过使用索引Q可以在查询的过E中使用优化隐藏器,提高pȝ的性能?/p>

四、烦(ch)引的~点
 (tng) (tng) (tng) 1.创徏索引和维护烦(ch)引要耗费旉Q这U时间随着数据量的增加而增?br /> (tng) (tng) (tng) 2.索引需要占物理I间Q除?jin)数据表占数据空间之外,每一个烦(ch)引还要占一定的物理I间Q如果要建立聚簇索引Q那么需要的I间׃(x)更大
 (tng) (tng) (tng) 3.当对表中的数据进行增加、删除和修改的时候,索引也要动态的l护Q降低了(jin)数据的维护速度

五、烦(ch)引分c?br /> (tng) (tng) (tng) 1.直接创徏索引和间接创建烦(ch)?br /> (tng) (tng) (tng) 直接创徏索引Q?CREATE INDEX mycolumn_index ON mytable (myclumn)
 (tng) (tng) (tng) 间接创徏索引Q定义主键约束或者唯一性键U束Q可以间接创建烦(ch)?br /> (tng) (tng) (tng) 2.普通烦(ch)引和唯一性烦(ch)?br /> (tng) (tng) (tng) 普通烦(ch)引:(x)CREATE INDEX mycolumn_index ON mytable (myclumn)
 (tng) (tng) (tng) 唯一性烦(ch)引:(x)保证在烦(ch)引列中的全部数据是唯一的,对聚烦(ch)引和非聚烦(ch)引都可以使用
 (tng) (tng) (tng) CREATE UNIQUE COUSTERED INDEX myclumn_cindex ON mytable(mycolumn)
 (tng) (tng) (tng) 3.单个索引和复合烦(ch)?br /> (tng) (tng) (tng) 单个索引Q即非复合烦(ch)?br /> (tng) (tng) (tng) 复合索引Q又叫组合烦(ch)引,在烦(ch)引徏立语句中同时包含多个字段名,最?6个字D?br /> (tng) (tng) (tng) CREATE INDEX name_index ON username(firstname,lastname)
 (tng) (tng) (tng) 4.聚簇索引和非聚簇索引(聚集索引Q群集烦(ch)?
 (tng) (tng) 聚簇索引Q物理烦(ch)引,与基表的物理序相同Q数据值的序L按照序排列
 (tng) (tng) (tng) CREATE CLUSTERED INDEX mycolumn_cindex ON mytable(mycolumn) WITH
 (tng) (tng) (tng) ALLOW_DUP_ROW(允许有重复记录的聚簇索引)
 (tng) (tng) 非聚烦(ch)引:(x)CREATE UNCLUSTERED INDEX mycolumn_cindex ON mytable(mycolumn)

六、烦(ch)引的使用
 (tng) (tng) 1.当字D|据更新频率较低,查询使用频率较高q且存在大量重复值是使用聚簇索引
 (tng) (tng) (tng) 2.l常同时存取多列Q且每列都含有重复值可考虑建立l合索引
 (tng) (tng) (tng) 3.复合索引的前导列一定好控制好,否则无法起到索引的效果。如果查询时前导列不在查询条件中则该复合索引不会(x)被用。前导列一定是使用最频繁的列
 (tng) (tng) (tng) 4.多表操作在被实际执行前,查询优化器会(x)Ҏ(gu)q接条gQ列出几l可能的q接Ҏ(gu)q从中找出系l开销最的最x案。连接条件要充䆾考虑带有索引的表、行数多的表Q内外表的选择可由公式Q外层表中的匚w行数*内层表中每一ơ查扄ơ数定Q乘U最ؓ(f)最x?br /> (tng) (tng) (tng) 5.where子句中对列的M操作l果都是在sqlq行旉列计算得到的,因此它不得不q行表搜索,而没有用该列上面的索引Q如果这些结果在查询~译时就能得刎ͼ那么可以被sql优化器优化,使用索引Q避免表搜烦(ch)(例:(x)select * from record where substring(card_no,1,4)=?378?
&& select * from record where card_no like ?378%?M对列的操作都导致表扫描Q它包括数据库函数、计表辑ּ{等Q查询时要尽可能操作移至等号右?br /> (tng) (tng) (tng) 6.where条g中的’in’在逻辑上相当于’or’,所以语法分析器?x)将in ('0','1')转化为column='0' or column='1'来执行。我们期望它?x)根据每个or子句分别查找Q再结果相加,q样可以利用column上的索引Q但实际上它却采用了(jin)"or{略"Q即先取出满x个or子句的行Q存入(f)时数据库的工作表中,再徏立唯一索引以去掉重复行Q最后从q个临时表中计算l果。因此,实际q程没有利用column上烦(ch)引,q且完成旉q要受tempdb数据库性能的媄(jing)响。in、or子句怼(x)使用工作表,使烦(ch)引失效;如果不生大量重复|可以考虑把子句拆开Q拆开的子句中应该包含索引
 (tng) (tng) (tng) 7.要善于用存储过E,它sql变得更加灉|和高?br />
from: http://www.knowsky.com/339315.html



weidagang2046 2006-10-27 12:13 发表评论
]]>
谈数据库设计技?/title><link>http://m.tkk7.com/weidagang2046/articles/72880.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Fri, 29 Sep 2006 09:39:00 GMT</pubDate><guid>http://m.tkk7.com/weidagang2046/articles/72880.html</guid><wfw:comment>http://m.tkk7.com/weidagang2046/comments/72880.html</wfw:comment><comments>http://m.tkk7.com/weidagang2046/articles/72880.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/weidagang2046/comments/commentRss/72880.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/weidagang2046/services/trackbacks/72880.html</trackback:ping><description><![CDATA[说到<a ><font color="#000000">数据?/font></a>Q我认ؓ(f)不能不先谈数据结构?996q_(d)在我初入大学学习(fn)计算机编E时Q当时的老师告诉我们说Q计机E序Q数据结构+法。尽现在的E序开发已由面向过Eؓ(f)主逐步q渡到面向对象ؓ(f)主,但我q是深深赞同8q前老师的告诉我们的公式Q计机E序Q数据结构+法。面向对象的E序开发,要做的第一件事是Q先分析整个E序中需处理的数据,从中提取出抽象模板,以这个抽象模板设计类Q再在其中逐步d处理其数据的函数(即算?Q最后,再给cM的数据成员和函数划分讉K权限Q从而实现封装? <p>  数据库的最初雏形据说源自美国一个奶牛场的记账薄(U质的,由此可见Q数据库q不一定是存储在电(sh)脑里的数据^_^)Q里面记录的是该奶牛场的收支账目Q程序员在将其整理、录入到?sh)脑中时从中受到启发。当按照规定好的数据l构所采集到的数据量大C定程度后Q出于程序执行效率的考虑Q程序员其中的(g)索、更新维护等功能分离出来Q做成单独调用的模块Q这个模块后来就慢慢发展、演变成现在我们所接触到的数据库管理系l?DBMS)——程序开发中的一个重要分支?/p><p>  下面q入正题Q首先按我个人所接触q的E序l数据库设计人员的功底分一下类Q?br />  Q、没有系l学?fn)过数据l构的程序员。这cȝ序员的作品往往只是他们的即兴玩P他们往往?fn)惯只设计有限的几个表,实现某类功能的数据全部塞在一个表中,各表之间几乎毫无兌。网上不的免费理软g都是q样的东西,当程序功能有限,数据量不多的时候,其程序运行v来没有什么问题,但是如果用其理比较重要的数据,风险性非常大?br />  Q、系l学?fn)过数据l构Q但是还没有开发过对程序效率要求比较高的管理Y件的E序员。这cMh多半刚从学校毕业不久Q他们在设计数据库表l构Ӟ严格按照教科书上的规定,LE-R囑֒3NF(别灰?j),所有的数据库设计高手都是从q一步开始的)。他们的作品Q对于一般的access型轻量的管理YӞ已经够用。但是一旦该pȝ需要添加新功能Q原有的数据库表差不多得q行大换血?br />  Q、第二类E序员,在经历过数次E序效率的提升,以及(qing)功能升的折腑֐Q终于升U成为数据库设计的老鸟Q第一cȝ序员g的高人。这cȝ序员可以胜Q二十个表以上的中型商业数据管理系l的开发工作。他们知道该在什么样的情况下保留一定的冗余数据来提高程序效率,而且其设计的数据库可拓展性较好,当用户需要添加新功能Ӟ原有数据库表只需做少量修改即可?br />  Q、在l历q上十个cM数据库管理Y件的重复设计后,W三cȝ序员中坚持下来没有{行,而是希望从中扑և“偷懒”窍门的有心(j)Z(x)慢慢觉?zhn)Q从而完成量变到质变的{换。他们所设计的数据库表结构有一定的q见Q能够预到未来功能升所需要的数据Q从而预先留下伏W。这cȝ序员目前大多晋成数据挖掘方面的高软g开发h员?br />  Q、第三类E序员或W四cȝ序员Q在对现有的各家数据库管理系l的原理和开发都有一定的ȝ后,要么在其基础上进行二ơ开发,要么自行开发一套有自主版权的通用数据库管理系l?/p><p>  我个人正处于W三cȝ末期Q所以下面所列出的一些设计技巧只适合W二cd部分W三cL据库设计人员。同Ӟ׃我很碰到有兴趣在这斚w深钻下去的同行,所以文中难免出现错误和遗漏Q在此先行声明,Ƣ迎大家指正Q不要藏U哦8)</p><p>  一、树(wi)型关pȝ数据?br />  不少E序员在q行数据库设计的时候都遇到q树(wi)型关pȝ数据Q例如常见的cd表,即一个大c,下面有若q个子类Q某些子cd有子c这L(fng)情况。当cd不确定,用户希望可以在Q意类别下d新的子类Q或者删除某个类别和其下的所有子c,而且预计以后其数量会(x)逐步增长Q此时我们就?x)考虑用一个数据表来保存这些数据。按照教U书上的教导Q第二类E序员大概会(x)设计出类DL(fng)数据表结构:(x)</p><p>cd表_1(Type_table_1)<br />名称     cd    U束条g   说明<br />type_id (tng) (tng)   (tng) int (tng) (tng) (tng)   (tng) (tng) 无重复   (tng) (tng) cd标识Q主?br />type_name   char(50) (tng) (tng) (tng) 不允ؓ(f)I?tng)?cd名称Q不允许重复<br />type_father (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng)?该类别的父类别标识,如果是顶节点的话讑֮为某个唯一?/p><p>  q样的设计短精(zhn),完全满3NFQ而且可以满用户的所有要求。是不是q样p呢?{案是NOQWhyQ?/p><p>  我们来估计一下用户希望如何罗列出q个表的数据的。对用户而言Q他当然期望按他所讑֮的层ơ关pMơ罗列出所有的cdQ例如这P(x)<br />ȝ?br />  cd1<br />    cd1.1<br />      cd1.1.1<br />    cd1.2<br />  cd2<br />    cd2.1<br />  cd3<br />    cd3.1<br />    cd3.2<br />  …?/p><p>  看看Z(jin)实现q样的列表显C??wi)的先序遍?Q要对上面的表进行多次(g)索?注意Q尽类?.1.1可能是在cd3.2之后d的记录,{案仍然是Nơ。这L(fng)效率对于量的数据没什么媄(jing)响,但是日后cd扩充到数十条甚至上百条记录后Q单单列一ơ类型就要检索数十次该表Q整个程序的q行效率׃敢恭l了(jin)。或许第二类E序员会(x)_(d)那我再徏一个(f)时数l或临时表,专门保存cd表的先序遍历l果Q这样只在第一ơ运行时(g)索数十次Q再ơ罗列所有的cd关系时就直接读那个(f)时数l或临时表就行了(jin)。其实,用不着再去分配一块新的内存来保存q些数据Q只要对数据表进行一定的扩充Q再Ҏ(gu)加类型的数量q行一下约束就行了(jin)Q要完成上面的列表只需一ơ检索就行了(jin)。下面是扩充后的数据表结构:(x)</p><p>cd表_2(Type_table_2)<br />名称     cd    U束条g    (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 说明<br />type_id (tng) (tng)   (tng) int (tng) (tng) (tng) (tng)   (tng) 无重复   (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cd标识Q主?br />type_name   char(50) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)?cd名称Q不允许重复<br />type_father (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)?该类别的父类别标识,如果是顶节点的话讑֮为某个唯一?br />type_layer (tng) (tng) (tng) char(6) (tng) (tng) (tng) (tng) 限定3?初始gؓ(f)000000 (tng) (tng) (tng) (tng) (tng) (tng) cd的先序遍历,主要为减检索数据库的次?/p><p>  按照q样的表l构Q我们来看看上面例子记录在表中的数据是怎样的:(x)</p><p>type_id (tng) (tng) (tng) (tng) (tng) type_name (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) type_father (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) type_layer<br />1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) ȝ别?tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)?0 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 000000<br />2 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cd1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 010000<br />3 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cd1.1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 2 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 010100<br />4 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cd1.2 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 2 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 010200<br />5 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cd2 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 020000<br />6 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cd2.1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 5 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 020100<br />7 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cd3 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 030000<br />8 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cd3.1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 7 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 030100<br />9 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cd3.2 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 7 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 030200<br />10 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cd1.1.1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 3 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 010101<br />…?/p><p>  现在按type_layer的大来(g)索一下:(x)SELECT * FROM Type_table_2 ORDER BY type_layer</p><p>列出记录集如下:(x)</p><p>type_id (tng) (tng) (tng) (tng) (tng) type_name (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) type_father (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) type_layer<br />1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) ȝ别?tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)?0 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 000000<br />2 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cd1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 010000<br />3 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cd1.1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 2 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 010100<br />10 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cd1.1.1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 3 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 010101<br />4 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cd1.2 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 2 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 010200<br />5 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cd2 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 020000<br />6 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cd2.1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 5 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 020100<br />7 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cd3 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 030000<br />8 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cd3.1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 7 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 030100<br />9 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cd3.2 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 7 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 030200<br />…?/p><p>  现在列出的记录顺序正好是先序遍历的结果。在控制昄cd的层ơ时Q只要对type_layer字段中的数D行判断,?位一l,如大?则向右移2个空根{当?dng)我这个例子中讑֮的限制条件是最?层,每层最多可?9个子cdQ只要按用户的需求情况修改一下type_layer的长度和位数Q即可更攚w制层数和子类别数。其实,上面的设计不单单只在cd表中用到Q网上某些可按树(wi)型列表显C的论坛E序大多采用cM的设计?/p><p>  或许有h认ؓ(f)QType_table_2中的type_father字段是冗余数据,可以除去。如果这P在插入、删除某个类别的时候,得对type_layer 的内容进行比较繁琐的判定Q所以我q没有消去type_father字段Q这也正W合数据库设计中适当保留冗余数据的来降低E序复杂度的原则Q后面我?x)D一个故意增加数据冗余的案例?/p><p>  <br />  二、商品信息表的设?br />  假设你是一家百货公司电(sh)脑部的开发h员,某天老板要求你ؓ(f)公司开发一套网上电(sh)子商务^収ͼ该百货公司有数千U商品出售,不过目前仅打先在网上销售数十种方便q输的商品,当然Q以后可能会(x)陆箋在该?sh)子商务q_上增加新的商品出售。现在开始进行该q_数据库的商品信息表的设计。每U出售的商品都会(x)有相同的属性,如商品编P商品名称Q商品所属类别,相关信息Q供货厂商,内含件数Q库存,q货P销售h(hun)Q优惠h(hun)。你很快p计出4个表Q商品类型表(Wares_type)Q供货厂商表(Wares_provider)Q商品信息表(Wares_info)Q?/p><p>商品cd?Wares_type)<br />名称     cd    U束条g    (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 说明<br />type_id (tng) (tng)   (tng) int (tng) (tng) (tng)   (tng) (tng) 无重复   (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cd标识Q主?br />type_name   char(50) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)?cd名称Q不允许重复<br />type_father (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)?该类别的父类别标识,如果是顶节点的话讑֮为某个唯一?br />type_layer (tng) (tng) (tng) char(6) (tng) (tng) (tng) (tng) 限定3?初始gؓ(f)000000 (tng) (tng) (tng) (tng) (tng) (tng) cd的先序遍历,主要为减检索数据库的次?/p><p>供货厂商?Wares_provider)<br />名称     cd    U束条g    (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 说明<br />provider_id (tng) (tng) int (tng) (tng) (tng)   (tng) (tng) 无重复   (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 供货商标识,主键<br />provider_name char(100) (tng) (tng) 不允ؓ(f)I?tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)?供货商名U?/p><p>商品信息?Wares_info)<br />名称     (tng) cd    U束条g    (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 说明<br />wares_id (tng) (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng)   (tng) 无重复   (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 商品标识Q主?br />wares_name (tng) (tng) (tng) (tng) char(100) (tng) 不允ؓ(f)I?tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)?商品名称<br />wares_type   int (tng) (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I           商品cd标识Q和W(xu)ares_type.type_id兌<br />wares_info (tng) (tng) (tng) (tng) char(200) (tng) 允许为空 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 相关信息<br />provider (tng) (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)?供货厂商标识Q和W(xu)ares_provider.provider_id兌<br />setnum (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) 初始gؓ(f)1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 内含件数Q默认ؓ(f)1<br />stock (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) 初始gؓ(f)0 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 库存Q默认ؓ(f)0<br />buy_price (tng) (tng) (tng) (tng) (tng) money (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)?q货?br />sell_price (tng) (tng) (tng) (tng) money (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)?销售h(hun)<br />discount (tng) (tng) (tng) (tng) (tng) (tng) money (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)?优惠?/p><p>  你拿着q?个表l老板(g)查,老板希望能够再添加一个商品图片的字段Q不q只有一部分商品有图片。OKQ你在商品信息表(Wares_info)中增加了(jin)一个haspic的BOOL型字D,然后再徏?jin)一个新表——商品图片表(Wares_pic)Q?/p><p>商品囄?Wares_pic)<br />名称     (tng) cd    U束条g    (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 说明<br />pic_id (tng) (tng) (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng)   (tng) (tng) 无重复   (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 商品囄标识Q主?br />wares_id (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)?所属商品标识,和W(xu)ares_info.wares_id兌<br />pic_address  char(200) (tng) (tng) 不允ؓ(f)I           囄存放路径</p><p>  E序开发完成后Q完全满板目前的要求,于是正式启用。一D|间后Q老板打算在这套^C推出新的商品销售,其中Q某cd品全部都需d“长度”的属性。第一轮折腾来?jin)……当?dng)你按照添加商品图片表的老方法,在商品信息表(Wares_info)中增加了(jin)一个haslength的BOOL型字D,又徏?jin)一个新表——商品长度表(Wares_length)Q?/p><p>商品长度?Wares_length)<br />名称     (tng) cd    U束条g    (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 说明<br />length_id (tng) (tng) (tng) (tng) int (tng) (tng) (tng)   (tng) (tng) 无重复   (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 商品囄标识Q主?br />wares_id (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)?所属商品标识,和W(xu)ares_info.wares_id兌<br />length  (tng) (tng) (tng) (tng) (tng) char(20) (tng) (tng) (tng) 不允ؓ(f)I           商品长度说明</p><p>  刚刚改完没多久,老板又打上一Ҏ(gu)的商品,q次某类商品全部需要添加“宽度”的属性。你咬了(jin)咬牙Q又照方抓药Q添加了(jin)商品宽度?Wares_width)。又q了(jin)一D|_(d)老板C的商品中有一些需要添加“高度”的属性,你是不是开始觉得你所设计的数据库按照q种方式增长下去Q很快就能变成一个迷宫呢Q那么,有没有什么办法遏制这U不可预见性,但却cM重复的数据库膨胀呢?我在阅读《敏捯Y件开发:(x)原则、模式与实践》中发现作者Dq类似的例子Q?.3 “Copy”程序。其中,我非常赞同敏捯Y件开发这个观点:(x)在最初几乎不q行预先设计Q但是一旦需求发生变化,此时作ؓ(f)一名追求卓的E序员,应该从头审查整个架构设计Q在此次修改中设计出能够满日后cM修改的系l架构。下面是我在需要添加“长度”的属性时所提供的修Ҏ(gu)案:(x)</p><p>  L商品信息?Wares_info)中的haspic字段Q添加商品额外属性表(Wares_ex_property)和商品额外信息表(Wares_ex_info)2个表来完成添加新属性的功能?/p><p>商品额外属性表(Wares_ex_property)<br />名称     (tng) cd    U束条g    (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 说明<br />ex_pid (tng) (tng) (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng)   (tng) (tng) 无重复   (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 商品额外属性标识,主键<br />p_name (tng) (tng) (tng) (tng) (tng) (tng) (tng) char(20) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)?额外属性名U?/p><p>商品额外信息?Wares_ex_info)<br />名称     (tng) (tng) (tng) cd    U束条g    (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 说明<br />ex_iid (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng)   (tng) (tng) 无重复   (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 商品额外信息标识Q主?br />wares_id (tng) (tng) (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)?所属商品标识,和W(xu)ares_info.wares_id兌<br />property_id  (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I           商品额外属性标识,和W(xu)ares_ex_property.ex_pid兌<br />property_value (tng) char(200) (tng) (tng) 不允ؓ(f)I?tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)?商品额外属性?/p><p>  在商品额外属性表(Wares_ex_property)中添?条记录:(x)<br />ex_pid (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) p_name<br />1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 商品囄<br />2 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 商品长度</p><p>  再在整个?sh)子商务q_的后台管理功能中q加一商品额外属性管理的功能Q以后添加新的商品时出现新的属性,只需利用该功能往商品额外属性表(Wares_ex_property)中添加一条记录即可。不要害怕变化,被第一颗子弹击中ƈ不是坏事Q坏的是被相同轨道飞来的W二颗、第三颗子弹M。第一颗子Ҏ(gu)得越早,所受的伤越重,之后的抵抗力也越?)<br />三、多用户?qing)其权限理的设?br />  开?a ><font color="#000000">数据?/font></a>理cȝ软gQ不可能不考虑多用户和用户权限讄的问题。尽目前市(jng)面上的大、中型的后台数据库系lY仉提供?jin)多用户Q以?qing)细x个数据库内某张表的权限设|的功能Q我个hQ一套成熟的数据库管理YӞq是应该自行设计用户理q块功能Q原因有二:(x)<br />  1.那些大、中型后台数据库pȝ软g所提供的多用户?qing)其权限讄都是针对数据库的共有属性,q不一定能完全满某些特例的需求;<br />  2.不要q多的依赖后台数据库pȝ软g的某些特D功能,多种大、中型后台数据库pȝ软g之间q不完全兼容。否则一旦日后需要{换数据库q_或后台数据库pȝ软g版本升Q之前的架构设计很可能无法重用?/p><p>  下面看看如何自行设计一套比较灵zȝ多用L(fng)理模块,卌数据库管理Y件的pȝ理员可以自行添加新用户Q修改已有用L(fng)权限Q删除已有用戗首先,分析用户需求,列出该数据库理软g所有需要实现的功能Q然后,Ҏ(gu)一定的联系对这些功能进行分c,x某类用户需使用的功能归Zc;最后开始徏表:(x)<br />  <br />功能?Function_table)<br />名称     cd    U束条g   说明<br />f_id (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng)   (tng) (tng) 无重复   (tng) (tng) 功能标识Q主?br />f_name (tng) (tng) (tng) (tng) (tng) (tng) (tng) char(20) (tng) (tng) (tng) 不允ؓ(f)I?tng)?功能名称Q不允许重复<br />f_desc (tng) (tng) (tng) (tng) (tng) (tng) (tng) char(50) (tng) (tng) (tng) 允许为空 (tng) (tng) (tng) (tng) 功能描述</p><p>用户l表(User_group)<br />名称     cd    U束条g   说明<br />group_id (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 无重复?tng) (tng) (tng) (tng) (tng) (tng)?用户l标识,主键<br />group_name (tng) (tng) (tng) char(20) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?用户l名U?br />group_power (tng) (tng) char(100) (tng) (tng) 不允ؓ(f)I?tng) (tng)?用户l权限表Q内容ؓ(f)功能表f_id的集?/p><p>用户?User_table)<br />名称     cd    U束条g   说明<br />user_id (tng) (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 无重复?tng) (tng) (tng) (tng) (tng) (tng)?用户标识Q主?br />user_name (tng) (tng) (tng) (tng) char(20) (tng) (tng) (tng) 无重复?tng) (tng) (tng) (tng) (tng) (tng)?用户?br />user_pwd (tng) (tng) (tng) (tng) (tng) char(20) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?用户密码<br />user_type (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?所属用L(fng)标识Q和User_group.group_id兌</p><p>  采用q种用户l的架构设计Q当需要添加新用户Ӟ只需指定新用h属的用户l;当以后系l需要添加新功能或对旧有功能权限q行修改Ӟ只用操作功能表和用户l表的记录,原有用户的功能即可相应随之变化。当?dng)q种架构设计把数据库理软g的功能判定移C(jin)前台Q得前台开发相对复杂一些。但是,当用h较大(10Z?Q或日后软g升的概率较大时Q这个代h值得的?/p><p><br />  四、简z的扚wm:n设计<br />  到m:n的关p,一般都是徏?个表Qm一个,n一个,m:n一个。但是,m:n有时?x)遇到批量处理的情况Q例如到图书馆借书Q一般都是允许用户同时借阅n本书Q如果要求按Ҏ(gu)询借阅记录Q即列出某个用户某次借阅的所有书c,该如何设计呢Q让我们建好必须?个表先:(x)</p><p>书籍?Book_table)<br />名称     cd    U束条g   说明<br />book_id (tng) (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 无重复?tng) (tng) (tng) (tng) (tng) (tng)?书籍标识Q主?br />book_no (tng) (tng) (tng) (tng) (tng) (tng) char(20) (tng) (tng) (tng) 无重复?tng) (tng) (tng) (tng) (tng) (tng)?书籍~号<br />book_name (tng) (tng) (tng) (tng) char(100) (tng) (tng) 不允ؓ(f)I?tng) (tng)?书籍名称<br />…?/p><p>借阅用户?Renter_table)<br />名称     cd    U束条g   说明<br />renter_id (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 无重复?tng) (tng) (tng) (tng) (tng) (tng)?用户标识Q主?br />renter_name (tng) (tng) char(20) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?用户姓名<br />…?/p><p>借阅记录?Rent_log)<br />名称     cd    U束条g   说明<br />rent_id (tng) (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 无重复?tng) (tng) (tng) (tng) (tng) (tng)?借阅记录标识Q主?br />r_id (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?用户标识Q和Renter_table.renter_id兌<br />b_id (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?书籍标识Q和Book_table.book_id兌<br />rent_date (tng) (tng) (tng) (tng) datetime (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?借阅旉<br />…?/p><p>  Z(jin)实现按批查询借阅记录Q我们可以再Z个表来保存批量借阅的信息,例如Q?/p><p>扚w借阅?Batch_rent)<br />名称     cd    U束条g   说明<br />batch_id (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 无重复?tng) (tng) (tng) (tng) (tng) (tng)?扚w借阅标识Q主?br />batch_no (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?扚w借阅~号Q同一批借阅的batch_no相同<br />rent_id (tng) (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?借阅记录标识Q和Rent_log.rent_id兌<br />batch_date (tng) (tng) (tng) datetime (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?扚w借阅旉</p><p>  q样的设计好吗?我们来看看ؓ(f)?jin)列出某个用hơ借阅的所有书c,需要如何查询?首先(g)索批量借阅?Batch_rent)Q把W合条g的的所有记录的rent_id字段的数据保存v来,再用q些数据作ؓ(f)查询条g带入到借阅记录?Rent_log)中去查询。那么,有没有什么办法改q呢Q下面给ZU简z的扚w设计Ҏ(gu)Q不需d新表Q只需修改一下借阅记录?Rent_log)卛_。修改后的记录表(Rent_log)如下Q?/p><p>借阅记录?Rent_log)<br />名称     cd    U束条g   说明<br />rent_id (tng) (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 无重复?tng) (tng) (tng) (tng) (tng) (tng)?借阅记录标识Q主?br />r_id (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?用户标识Q和Renter_table.renter_id兌<br />b_id (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?书籍标识Q和Book_table.book_id兌<br />batch_no (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?扚w借阅~号Q同一批借阅的batch_no相同<br />rent_date (tng) (tng) (tng) (tng) datetime (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?借阅旉<br />…?/p><p>  其中Q同一ơ借阅的batch_no和该批第一条入库的rent_id相同。D例:(x)假设当前最大rent_id?4Q接着某用户一ơ借阅?本书Q则扚w插入?条借阅记录的batch_no都是65。之后另外一个用L(fng)?jin)一套碟Q再插入出租记录的rent_id?8。采用这U设计,查询扚w借阅的信息时Q只需使用一条标准T_SQL的嵌套查询即可。当?dng)q种设计不符?NFQ但是和上面标准?NF设计比v来,哪一U更好呢Q答案就不用我说?jin)吧?/p><p><br />  五、冗余数据的取舍<br />  上篇的“树(wi)型关pȝ数据表”中保留?jin)一个冗余字D,q里的例子更q一步——添加了(jin)一个冗余表。先看看例子Q我原先所在的公司Z(jin)解决员工的工作餐Q和附近的一家小馆联系Q每天吃饭记账,费用按h数^摊,月底由公司现金结,每个人每个月的工作餐费从工资中扣除。当?dng)每天吃饭的h员和人数都不是固定的Q而且Q由于每工作餐的所点的菜色不同Q每的p也不相同。例如,星期一中餐5?0元,晚餐2?0Q星期二中餐6?6元,晚餐3?8元。ؓ(f)?jin)方便计每个h每个月的工作费Q我写了(jin)一个简陋的餐记̎理E序Q数据库里有3个表Q?/p><p>员工?Clerk_table)<br />名称     cd    U束条g   说明<br />clerk_id (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 无重复?tng) (tng) (tng) (tng) (tng) (tng)?员工标识Q主?br />clerk_name (tng) (tng) (tng) char(10) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?员工姓名</p><p>每餐总表(Eatdata1)<br />名称     cd    U束条g   说明<br />totle_id (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 无重复?tng) (tng) (tng) (tng) (tng) (tng)?每餐总表标识Q主?br />persons (tng) (tng) (tng) (tng) (tng) (tng) char(100) (tng) (tng) 不允ؓ(f)I?tng) (tng)?餐员工的员工标识集?br />eat_date (tng) (tng) (tng) (tng) (tng) datetime (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?餐日期<br />eat_type (tng) (tng) (tng) (tng) (tng) char(1) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?餐cdQ用来区分中、晚?br />totle_price (tng) (tng) money (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?每餐总花?br />persons_num (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?餐人数</p><p>餐计费l表(Eatdata2)<br />名称     cd    U束条g   说明<br />id (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 无重复?tng) (tng) (tng) (tng) (tng) (tng)?餐计费l表标识Q主?br />t_id (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?每餐总表标识Q和Eatdata1.totle_id兌<br />c_id (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?员工标识标识Q和Clerk_table.clerk_id兌<br />price (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) money (tng) (tng) (tng) (tng) (tng) (tng) 不允ؓ(f)I?tng) (tng)?每h每餐p</p><p>  其中Q就计费细?Eatdata2)的记录就是把每餐总表(Eatdata1)的一条记录按餐员工qx拆开Q是个不折不扣的冗余表。当?dng)也可以把每餐总表(Eatdata1)的部分字D合q到餐计费l表(Eatdata2)中,q样每餐总表(Eatdata1)成?jin)冗余表Q不q这h设计出来的就计费细表重复数据更多,相比来说q是上面的方案好些。但是,是餐计费l表(Eatdata2)q个冗余表,在做每月每h费l计的时候,大大化了(jin)~程的复杂度Q只用类D么一条查询语句即可统计出每h每月的寄次数和费dQ?/p><p>SELECT clerk_name AS personname,COUNT(c_id) as eattimes,SUM(price) AS ptprice FROM Eatdata2 JOIN Clerk_tabsle ON (c_id=clerk_id) JOIN eatdata1 ON (totleid=tid) WHERE eat_date>=CONVERT(datetime,'"&the_date&"') AND eat_date<DATEADD(month,1,CONVERT(datetime,'"&the_date&"')) GROUP BY c_id</p><p>  惌一下,如果不用q个冗余表,每次l计每h每月的餐Ҏ(gu)d时会(x)多麻?ch),E序效率也够呛。那么,到底什么时候可以增加一定的冗余数据呢?我认为有2个原则:(x)</p><p>  Q、用L(fng)整体需求。当用户更多的关注于Q对数据库的规范记录按一定的法q行处理后,再列出的数据。如果该法可以直接利用后台数据库系l的内嵌函数来完成,此时可以适当的增加冗余字D,甚至冗余表来保存q些l过法处理后的数据。要知道Q对于大扚w数据的查询,修改或删除,后台数据库系l的效率q远高于我们自己~写的代码?br />  Q、简化开发的复杂度。现代Y件开发,实现同样的功能,Ҏ(gu)有很多。尽不必要求程序员_N绝大部分的开发工具和q_Q但是还是需要了(jin)解哪U方法搭配哪U开发工L(fng)E序更简z,效率更高一些。冗余数据的本质是用空间换旉Q尤其是目前g的发展远q高于YӞ所以适当的冗余是可以接受的。不q我q是在最后再一下:(x)不要q多的依赖^台和开发工L(fng)Ҏ(gu)来化开发,q个度要是没把握好的话,后期l护升?x)栽大跟头的?br /><br />from: <a >http://www.knowsky.com/4937.html</a></p><img src ="http://m.tkk7.com/weidagang2046/aggbug/72880.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/weidagang2046/" target="_blank">weidagang2046</a> 2006-09-29 17:39 <a href="http://m.tkk7.com/weidagang2046/articles/72880.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关系型数据库设计?/title><link>http://m.tkk7.com/weidagang2046/articles/72878.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Fri, 29 Sep 2006 09:37:00 GMT</pubDate><guid>http://m.tkk7.com/weidagang2046/articles/72878.html</guid><wfw:comment>http://m.tkk7.com/weidagang2046/comments/72878.html</wfw:comment><comments>http://m.tkk7.com/weidagang2046/articles/72878.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/weidagang2046/comments/commentRss/72878.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/weidagang2046/services/trackbacks/72878.html</trackback:ping><description><![CDATA[在这文章的W二章中Q我们已l徏立了(jin)一个供我们使用的非常简单的W话数据库,q个库中只包括了(jin)一个名叫Jokes的数据表。这作ؓ(f)我们使用MySQL数据库的入门已经是够了(jin)Q但是在关系型数据库的设计中q有很多其它的东ѝ在q一章中Q我们会(x)Ҏ(gu)们的例子q行扩充Q学?fn)一些有关MySQL的新知识Qƈ试图理解q掌握关pd数据库所能提供的功能?br /><br />首先Q我们得说明我们对许多问题的解决只是不正规的Q也是说非正式的)(j)。正如你在许多计机U学专业中了(jin)解的那样Q数据库设计是一个严肃的领域Q数据库设计必须包括对它的测试ƈ?x)涉及(qing)到一些数学的原理。但q些可能是超q我们这文章的范围?jin)。要得到更多的信息,你可以停下来到http://www.datamodel.org/ȝ看,在那儿你可以看到许多好的书籍Qƈ得到一些关于这个问题的有用的资源?br /><br /><b>l予应有的权?/b><br />在开始之前,让我们回忆一下我们的Jokes数据表的l构Q这个表包含三个列:(x)ID、JokeText?JokeDate。这些列可以使我们标识笑话(IDQ,明了(jin)他们的内容(JokeTextQ以?qing)他们被加入的时_(d)JokeDateQ?br /><br />现在我们惌保存我们的笑话中的其它一些信息:(x)提交者的姓名。这看上d自然Q我们需要在我们的Jokes数据表中d一个新的列。SQL的ALTER命o(h)Q我们在之前没看到过q个命o(h)Q可以帮助我们完成这件事。用mysql命o(h)行程序登录到MySQL服务器,选择你的数据库(如果你用我们在W二章中的命名,数据库名应该是jokeQ,然后输入下面的命令:(x)<br /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="0" width="580" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6">mysql> ALTER TABLE Jokes ADD COLUMN<br />-> AuthorName VARCHAR(100);<br /></td></tr></tbody></table><br />q将?x)在我们的数据表中增加一个叫AuthorName的列。其数据cd是一个可变长度的字符Ԍ其最大长度是100个字W(q对于最复杂的名字应该也是够了(jin)Q。让我们再添加一列用来保存作者的e-mail地址Q?br /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="0" width="580" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6">mysql> ALTER TABLE Jokes ADD COLUMN<br />-> AuthorEMail VARCHAR(100);<br /></td></tr></tbody></table><br />要得到更多的有关ALTER命o(h)的信息,请参看MySQL参考手册。要认我们是不是正地d?jin)两列,你可以要求MySQL为我们对q个表进行描qͼ(x)<br /><img src="http://www0.ccidnet.com/tech/web/2001/12/03/image/5-01.gif" /><br />看上d不错。明昑֜Q我们需要对我们在第四章中徏立的d新笑话的HTML以及(qing)PHP格式的代码进行调_(d)但是我们?x)把q留l你作ؓ(f)一个练?fn)。用UPDATE查询Q你现在可以对表中的所有笑话添加作者的详细资料。然而,在你开始接受这个数据结构之前,我们必须考虑一下我们在q儿选择的设计是否确当。在q种情况下,我们?x)发C些我们还没有做到的事情?br /><br /><b>一个基本的规则Q保持事物的分离</b><br />在你建立数据库驱动的|站的过E中Q你已经觉得仅仅是有一个笑话列表是不够的。事实上Q除?jin)你自己的笑话以外,你开始接收其他h提交的笑话。你军_做一个让全世界h都可以共享笑话的|站。你有没有听说过Internet?sh)?jing)数据库(IMDBQ?实际上你现在做的是InternetW话数据库(IJDBQ!Ҏ(gu)一个笑话添加作者的姓名和e-mail地址肯定是最Ҏ(gu)惛_的办法,但是q种Ҏ(gu)?x)导致一些潜在的问题Q?br /><br />如果一个经常投E的名叫Joan Smith的h改变?jin)她的e-mail地址会(x)发生什么什么情况呢Q她?x)开始用新地址来提交新的笑话,但是对于所有的旧笑话,你所能看到的q是旧的地址。从你的数据库来看,你也许只能认为有两h名字都叫Joan Smith的h在向你的数据库中提交W话。如果她是特别体贴的Q她也许?x)通知你改变地址Q你可以所有的旧笑话改成新的地址Q但是如果你遗漏?jin)一个,那就意味着你的数据库中存储?jin)错误的信息。数据库设计专家这U类型的问题UCZ个“更正异常”?br /><br />很自然地你会(x)惛_从你的数据库中得到所有曾l向你的站点提交q笑话的人的列表。实际上Q你可以使用下面的查询很Ҏ(gu)地得到这L(fng)列表Q?br /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="0" width="580" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6">mysql> SELECT DISTINCT AuthorName, AuthorEMail -> FROM Jokes;</td></tr></tbody></table><br />上面查询中DISTINCT是告诉MySQL不输出重复的l果行。例如,如果Joan Smith向我们的站点提交q?0个笑话,如果我们使用?jin)DISTINCT选项Q她的名字和e-mail地址会(x)只在列表中出Cơ,否则?x)出?0ơ?br /><br />如果因ؓ(f)某种原因Q你军_要从数据库中删除某个特定的作者所提交的所有笑话,但是Q与此同Ӟ你将不能再通过e-mail与他们联p!而你的e-mail清单可能是你的网站的收入的主要来源,所以你q不惛_因ؓ(f)你不喜欢他们提交的笑话,删除他们的e-mail地址。数据库设计专家这UC为“删除异常”?br /><br />你ƈ不能保证不会(x)出现q样的情况:(x)Joan Smith输入的姓名一?x)儿是“Joan Smith”,一?x)儿是“J. Smith”,一?x)儿又是“Smith, Joan”。这得你要确定一个特定的作者变得非常困难(特别是Joan Smith又经怋用几个不同的email地址的时候)(j)?br /><br />q些问题的解军_实很单。只要你不再作者的信息存储到Jokes数据表中Q而是建立一个新的数据表来存储作者列表。因为我们在Jokes数据表中使用?jin)一个叫I(xin)D的列来用一个数据标识每个笑话,所以我们在新的数据表中使用?jin)同样名字的列来标识我们的作者。我们可以在我们的Jokes表中使用“author ID's”来建立W话和他的作者之间的兌。全部的数据库设计应该是q样的:(x) <br /><div align="center"><img src="http://www0.ccidnet.com/tech/web/2001/12/03/image/5-04.gif" /></div><br />上面的两个表包含?jin)三个笑话和两个作者。Jokes表的AID列(“Author ID”的~写Q提供了(jin)两个表之间的兌Q指出Kevin Yank 提交?jin)笑?和笑?QJoan Smith提交?jin)笑?Q。在q里Q你q需要注意到每一个作者只?x)在数据库中出现一ơ,而且他们是独立于他们提交的笑话而存在的Q因此我们已l解决了(jin)我们上面提出的那些问题?br /><br />q个数据库设计的最重要的特征是Q因为我们要存储两种cd的事物(W话和作者)(j)Q所以我们设计两个表。这是我们在数据库设计中要遵守的一个基本规则:(x)对于每一个要存储其信息的实体Q或事物Q,我们都应该给他一个自q表?br /><br />重新生成上面的数据是非常单的Q只要用两个CREATE TABLE 查询p?jin)?j)Q但是因为我们想要在做这些变动时不会(x)有破坏性的效果Q也是说不?x)丢失我们已l存入的W话Q,所以我们需要再ơ用ALTER命o(h)?首先Q我们删除Jokes表中有关作者的列:(x)<br /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="0" width="580" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6">mysql> ALTER TABLE Jokes DROP COLUMN AuthorName;<br />Query OK, 0 rows affected (0.00 sec)<br />Records: 0 Duplicates: 0 Warnings: 0<br />mysql> ALTER TABLE Jokes DROP COLUMN AuthorEMail;<br />Query OK, 0 rows affected (0.00 sec)<br />Records: 0 Duplicates: 0 Warnings: 0<br /></td></tr></tbody></table><br />现在我们建立我们的新的数据表Q?<br /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="0" width="580" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6">mysql> CREATE TABLE Authors (<br />-> ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,<br />-> Name VARCHAR(100),<br />-> EMail VARCHAR(100)<br />-> );<br /></td></tr></tbody></table><br />最后,我们在我们的Jokes表中dAID列:(x)<br />mysql> ALTER TABLE Jokes ADD COLUMN AID INT;<br />现在剩下来的是向新的表中添加一些作者,q过填充AID列来Ҏ(gu)据库中已l存在的W话指定作者?br /><br /><b>处理多个?/b><br />现在我们的数据被分布在两个表当中Q要从其中获得数据看上去变得更加复杂?jin)。例如,我们最初的目标是:(x)昄一个笑话的列表q在每一个笑话后面显CZ者的姓名和e-mail地址。在我们的单表结构中Q要获得所有的信息Q只需要在我们的PHP代码中用一个SELECT语句p?jin)?x)<br /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="0" width="580" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6">$jokelist = mysql_query(<br />"SELECT JokeText, AuthorName, AuthorEMail ".<br />"FROM Jokes");<br />while ($joke = mysql_fetch_array($jokelist)) {<br />$joketext = $joke["JokeText"];<br />$name = $joke["AuthorName"];<br />$email = $joke["AuthorEMail"]; // Display the joke with author information<br />echo( "<P>$joketext<BR>" .<br />"(by QHREF='mailto:$email'Q?name)</P>" );<br />}<br /></td></tr></tbody></table><br />在我们的新系l中Q这样做初看h是不可能?jin)。因为有x个笑话的作者的详细资料不是存储在Jokes表中Q我们可能想到的一个解x案是我们对于我们惌昄的笑话单独地获得q些资料。代码将是这L(fng)Q?br /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="0" width="580" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6">// Get the list of jokes<br />$jokelist = mysql_query(<br />"SELECT JokeText, AID FROM Jokes");<br />while ($joke = mysql_fetch_array($jokelist)) {<br />// Get the text and Author ID for the joke<br />$joketext = $joke["JokeText"];<br />$aid = $joke["AID"];<br />// Get the author details for the joke<br />$authordetails = mysql_query(<br />"SELECT Name, Email FROM Authors WHERE ID=$aid");<br />$author = mysql_fetch_array($authordetails);<br />$name = $author["Name"];<br />$email = $author["EMail"];<br />// Display the joke with author information<br />echo( "<P>$joketext<BR>" .<br />"(by QA HREF='mailto:$email'Q?name)</P>" );<br />}<br /></td></tr></tbody></table><br />很؜乱,而且对于每一个显C的W话都包含了(jin)一个对数据库的查询Q这会(x)我们的页面的昄非常~慢。现在看来,“老方法”可能是更好的解x案,管它有其自w的q?br />q运的是Q关pd数据库可以很Ҏ(gu)地处理多个表中的数据Q在SELECT语句中用一个新的被UC为“join”的格式Q我们可以找C全其的办法。连接可以我们象对存储在单个表中的数据那样对待多个表中的关联数据。一个连接的格式应该是这L(fng)Q?br /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="0" width="580" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6">mysql> SELECT <columns> FROM <tables><br />-> WHERE <condition(s) for data to be related>;<br /></td></tr></tbody></table><br />在我们目前的情况下,我们所需要的列是Jokes表中的JokeText列以?qing)Authors表中的Name列和Email列。Jokes表和Authors表的兌条g是Jokes表中的AID列的值等于Authors表中的ID列的倹{下面是一个连接的例子Q前两个查询只是用来昄我们的两个表中所包含的内容)(j)Q?br /><img src="http://www0.ccidnet.com/tech/web/2001/12/03/image/5-02.gif" /><br />现在明白?jin)吗Q第三个SELECT的结果就是一个连接,它将存储在两个表中的数据兌数据昄C(jin)一个结果表中,管我们的数据是存储在两个表中的Q我们仍然可以用一个数据库查询p得我们的Web面所需要的W话列表的全部信息?br /><br />在这里,要注意一个问题,因ؓ(f)在两个表中都有一个叫I(xin)D的列Q所以我们在用到Authors表中的ID列时我们必须指定表名QAuthors.IDQ。如果我们没有指定表名,MySQL无法知道我们指的是哪一个表中的IDQ这?x)导致这L(fng)一个错误:(x)<br /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="0" width="580" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6">mysql> SELECT LEFT(JokeText,20), Name, Email<br />-> FROM Jokes, Authors WHERE AID = ID;<br />ERROR 1052: Column: 'ID' in where clause is ambiguous<br /></td></tr></tbody></table><br />现在我们知道如何有效率地从我们的两个表中获取信息?jin),我们可以利用q接来重新编写我们的W话列表的程序:(x)<br /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="0" width="580" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6">$jokelist = mysql_query(<br />"SELECT JokeText, Name, EMail " .<br />"FROM Jokes, Authors WHERE AID=Authors.ID");<br />while ($joke = mysql_fetch_array($jokelist)) {<br />$joketext = $joke["JokeText"];<br />$name = $joke["Name"];<br />$email = $joke["EMail"];<br />// Display the joke with author information<br />echo( "<P>$joketext<BR>" .<br />"(by QA HREF='mailto:$email'Q?name)</P>" );<br />}<br /></td></tr></tbody></table><br />随着你对数据库的使用Q你?x)越来越发现q接的功能有多大的意义。例如,下面的查询用来显C所有由Joan Smith写的W话Q?br /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="0" width="580" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6">mysql> SELECT JokeText FROM Jokes, Authors WHERE<br />-> Name="Joan Smith" AND AID=Authors.ID;<br /></td></tr></tbody></table><br />上面的查询的输出l果仅仅来源于Jokes表,但是我们使用?jin)一个连接来通过存储在Authors表中的值搜索笑话。在我们的这文章中?x)有更多的这L(fng)_y的查询,在实际应用中Q连接是l常?x)被使用的,而且在绝大多数的情况下,q会(x)很大E度地简化我们的工作Q?br /><br /><b>单的数据关系</b><br />对于l定的情늚最好的数据模型往往军_于我们所工作的两U数据之间的关系cd。我q篇文章中,我们对典型的关pȝ型进行研IӞq学?x)如何在一个关pd数据中用最好的Ҏ(gu)描述它?br /><br />对于单的一对一的关p,只要用一个表p够了(jin)。一对一关系的一个例子就是我们在前面已经看到的在W话数据库中的每一个作者的e-mail地址。因为对于每一个作者只有一个e-mail地址Q而且对于一个e-mail地址对应的也只有一个作者,它们分C个数据库中是没有道理的?br /><br />多对一的关pd能会(x)E微复杂一点,但是在之前其实我们也已经解决?jin)这个问题,我们的数据库中的每一个笑话只?x)有一个作者,但是同一个作者可能写?jin)很多笑话。笑话和作者之间的关系是一个多对一的关pR我们曾l有q一个初步的解决Ҏ(gu)Q那是与q个W话兌的作者的信息也促(j)成在同一个数据库中。但是这样做Q对于同一个数据会(x)有许多拷贝,q不仅会(x)在同步上造成困难Q而且?x)浪费空间。将数据分开C个数据表中ƈ使用一个ID列来q接两个表(象上面所说的那样使用q接Q,所有的问题?x)得到很好的解决?br /><br />到目前ؓ(f)止,我们q没接触C对多的关p,但是惌q样的一个关pd该是不困隄。在我们之前建立的数据库中,我们假定一个作者只有一个e-mail地址。事实上情况q不Lq样的,作出q个限制的理由只是因为我们只需要一个e-mail地址来与作者联pR我们简单地假设?jin)作者M(x)输入他们常用的e-mail地址Q或者至是一个正怋用的e-mail地址。如果我们想要支持多个e-mail地址Q我们将面对一个一对多的关p(一个作者会(x)有几个e-mail地址Q但是一个e-mail地址只会(x)与一个确定的作者对应)(j)?br /><br />一个没有经验的数据库设计者面对一个一对多的关pLQ他首先?x)想到的是试图把多个数据存储C个数据库域中Q就象这P(x)<br /><div align="center"><img src="http://www0.ccidnet.com/tech/web/2001/12/03/image/5-05.gif" /></div><br />q种l构在投入用后Q要从数据库中获得一个单个的e-mail地址Q将不得不通过搜烦(ch)逗号Q或者你所选择的用来分隔的其他W号Q来分割字符Ԍq样做ƈ不简单,而且?x)很耗时。设想一下如果要用PHP来删除某个作者的某个e-mail地址Q那也将?x)是很困隄事。另外,对于EMail列我们需要很长的长度Q这?x)导致磁盘空间的费Q因为大多数的作者都只会(x)有一个e-mail地址?br /><br />解决一对多的关pd我们上面解决多对一的关pL非常cM的。实际上两者之前只是一个简单的颠倒。我们可Authors表分成两个表QAuthors和EMailsQ然后在EMails表中使用作者的IDQAIDQ这L(fng)一个列来实C个表之间的连接:(x)<br /><div align="center"><img src="http://www0.ccidnet.com/tech/web/2001/12/03/image/5-06.gif" /></div><br />使用一个连接,昄某个作者的所有E-mail地址会(x)是很单的Q?br /><img src="http://www0.ccidnet.com/tech/web/2001/12/03/image/5-03.gif" /><br /><b>多对多的关系</b><br />OkQ现在你有了(jin)一个发布在你的|站上的E_增长的笑话数据库。事实上Q这U增长是非常q速的Q笑话的数量?x)变得难以管理!你的讉K者将面对一个庞大的面Q在q个面上杂乱地排列?jin)数以百计的W话。现在,我们不得不考虑作一些变动了(jin)?br /><br />你决定将你的W话攄C同的目录中,q些目录可能是“Knock-KnockW话”、“Crossing the RoadW话”、“LawyerW话”和“PoliticalW话”。记住我们之前的处理规则Q因为我们的W话目录是一个不同类型的“事物”,所以我们要为它们徏立一个新的数据表Q?br /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="0" width="580" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6">mysql> CREATE TABLE Categories (<br />-> ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,<br />-> Name VARCHAR(100),<br />-> Description TEXT<br />-> );<br />Query OK, 0 rows affected (0.00 sec)<br /></td></tr></tbody></table><br />对你的笑话定义其所属目录将?x)是一个困隄d。因Z个“political”笑话可能也是一个“crossing the road”笑话,同样Q一个“knock-knock”可能也是一个“lawyer”笑话。一个单个的W话可能属于许多目录Q每一个目录也?x)包含许多笑话。这是一个多对多的关pR?br /><br />许多没有l验的设计者又?x)想到将几个数据存储C个列中,最直接的解x案是在Jokes表中增加Categories列,q在其中列DW话所属的目录的ID。现在适用我们的第二个处理规则?jin)?x)如果你需要在一个列中存储多个|那证明你的设计可能是有缺L(fng)?br /><br />描述一个多对多关系的正方法是使用一个“lookup”表。这个表不包含Q何实际的数据Q只是用来定义关联的事物。这儿是我们q部分的数据库设计的C意图:(x)<br /><div align="center"><img src="http://www0.ccidnet.com/tech/web/2001/12/03/image/5-07.gif" /></div><br />JokeLookup 表将W话的IDQJIDQ的目录的IDQCIDQ进行了(jin)兌。从上面的例子我们可以看出,以“How many lawyers...”开头的W话既属于“Lawyer”目录,又属于“Light Bulb”目录?br /><br />建立lookup表的Ҏ(gu)和徏立其他表的方法基本一栗不同点在于选择主键。我们之前所建立的每一个表都有一个名为ID的列Q这一列被我们定义为PRIMARY KEY。将一个列定义Z键意味着q一列不?x)出现重复倹{而且可以加快Zq一列的q接操作的速度?<br /><br />对于我们的lookup表来_(d)没有一个单个的列可以保证不出现重复倹{每一个笑话可以属于几个目录,所以一个joke ID可能?x)出现多ơ;同样的,一个目录可能包含多个笑话,所以一个category ID也可能会(x)出现多次。我们所要求的只是相同的数据对不应重复出现。因为我们这个表的唯一作用是用来实现q接Q所以用主键来提高q接操作的速度Ҏ(gu)们肯定有价倹{所以,我们通常?x)?f)lookup表徏立一个多列的主键Q?br /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="0" width="580" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6">mysql> CREATE TABLE JokeLookup (<br />-> JID INT NOT NULL,<br />-> CID INT NOT NULL,<br />-> PRIMARY KEY(JID,CID)<br />-> );</td></tr></tbody></table><br />现在我们的表中的JID和CID共同l成?jin)这个表的主键。保持lookup表中数据的唯一性是有h(hun)值的Q防止重复定义某一个笑话属于某一个目录)(j)Q而且q会(x)提高q个表用来连接时的速度?br />使用我们的lookup表中包含的目录分配,我们可以使用q接来徏立几个有而且非常实用的查询。下面的查询列出?jin)“Knock-Knock”目录下的所有笑话:(x)<br /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="0" width="580" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6">mysql> SELECT JokeText<br />-> FROM Jokes, Categories, JokeLookup<br />-> WHERE Name="Knock-Knock" AND<br />-> CID=Categories.ID AND JID=Jokes.ID;<br /></td></tr></tbody></table><br />下面q个查询列D?jin)以“How many lawyers...”开头的W话所属的所有目录:(x) <br /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="0" width="580" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6">mysql> SELECT Categories.Name<br />-> FROM Jokes, Categories, JokeLookup<br />-> WHERE JokeText LIKE "How many lawyers%"<br />-> AND CID=Categories.ID AND JID=Jokes.ID;<br /></td></tr></tbody></table><br />下面的查询,同时使用?jin)我们的Authors表Ş成了(jin)一个四个表的连接(Q!Q)(j)Q列举了(jin)写过 Knock-KnockW话的所有作者的名字Q?br /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="0" width="580" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6">mysql> SELECT Authors.Name<br />-> FROM Jokes, Authors, Categories, JokeLookup<br />-> WHERE Categories.Name="Knock-Knock"<br />-> AND CID=Categories.ID AND JID=Jokes.ID<br />-> AND AID=Authors.ID;<br /></td></tr></tbody></table><br /><b>l语</b><br />q一章中Q我们学?fn)?jin)正确的数据库设计的基本原则,以及(qing)MySQLQ实际上Q对其他关系型数据库同样适用Q如何对描述事g之间的不同类型的关系提供支持。我们不仅仅探讨?jin)一对一的关p,q详l讨Z(jin)多对一、一对多以及(qing)多对多的关系?br /><br />在这一q程中,我们q学?fn)?jin)一些有关SQL命o(h)的新的东ѝ特别的Q我们学?fn)?jin)如何使用一个SELECT去连接多个表中的数据q将其反映到一个结果集中?br /><br />在第六章中,我们用我们已l获得的知识Qƈ加上很少的一些新知识Q去用PHP构徏一个内容管理系l。我们希望这个系l可以提供一个可定制的、安全的、基于Web的界面来理数据库的内容Q而不再是在MySQL命o(h)行中来解决问题?br /><br />from: <a >http://www0.ccidnet.com/tech/web/2001/12/03/92_3846.html</a><img src ="http://m.tkk7.com/weidagang2046/aggbug/72878.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/weidagang2046/" target="_blank">weidagang2046</a> 2006-09-29 17:37 <a href="http://m.tkk7.com/weidagang2046/articles/72878.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQL查询某类中的最高分http://m.tkk7.com/weidagang2046/articles/63589.htmlweidagang2046weidagang2046Tue, 15 Aug 2006 01:16:00 GMThttp://m.tkk7.com/weidagang2046/articles/63589.htmlhttp://m.tkk7.com/weidagang2046/comments/63589.htmlhttp://m.tkk7.com/weidagang2046/articles/63589.html#Feedback0http://m.tkk7.com/weidagang2046/comments/commentRss/63589.htmlhttp://m.tkk7.com/weidagang2046/services/trackbacks/63589.htmlclassID (tng)  (tng)className
1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 衣服
2 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)  (tng) 裤子
5 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)  (tng) 帽子
10 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 鞋子

表productInfo有如下记?

productID (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)  (tng) (tng) (tng)productName (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)parentID (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) clickNum

1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 男士衣服 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)90 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) --衣服cd中这条记录的点击率最?br />2 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 奛_衣服 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 80
3 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 男士裤子 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)2 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 70
4 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 奛_裤子 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)2 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 90 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) --裤子cd中这条记录点ȝ最?br />5 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 男士帽子 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)5 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)  (tng) (tng)15
6 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 奛_帽子 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)5 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)  (tng)30 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)--帽子cd中这条点ȝ最?br />7 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 男士鞋子 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)10 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 65 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)--鞋子cd中这条点ȝ最?br />8 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 奛_鞋子 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)10 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)52
9 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 奛_鞋子1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)10 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)54

现在要求分别把衣?裤子,帽子,鞋子q些cd中点ȝ最高的一条记录找出来,然后再降序排?l果应如?

productID (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) productName (tng) (tng) (tng) (tng) (tng) (tng) (tng)  (tng) (tng) (tng) clickNum
1 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)  (tng)男士衣服 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)  (tng)90
4 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)奛_裤子 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)90
7 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)男士鞋子 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)65
6 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)奛_帽子 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)30

select (tng)* (tng)from (tng)goods (tng)as (tng)g1 (tng)where (tng)

 (tng) (tng) (tng) (tng)
not (tng)exists (tng)
 (tng) (tng) (tng) (tng)
 (tng) (tng) (tng) (tng)(
select (tng)* (tng)from (tng)goods (tng)as (tng)g2 (tng)where
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)g1.parentId (tng)
= (tng)g2.parentId (tng)and (tng)g2.clickNum (tng)> (tng)g1.clickNum
 (tng) (tng) (tng) (tng))
 (tng) (tng) (tng) (tng) (tng) (tng)

weidagang2046 2006-08-15 09:16 发表评论
]]>
SQL Server存储q程~写和优化措?/title><link>http://m.tkk7.com/weidagang2046/articles/62873.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Thu, 10 Aug 2006 14:33:00 GMT</pubDate><guid>http://m.tkk7.com/weidagang2046/articles/62873.html</guid><wfw:comment>http://m.tkk7.com/weidagang2046/comments/62873.html</wfw:comment><comments>http://m.tkk7.com/weidagang2046/articles/62873.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/weidagang2046/comments/commentRss/62873.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/weidagang2046/services/trackbacks/62873.html</trackback:ping><description><![CDATA[  一、适合读者对象:(x)<a class="bluekey" target="_blank"><font color="#002c99">数据库开?/font></a>E序员,数据库的数据量很多,涉及(qing)到对SPQ?a class="bluekey" target="_blank"><font color="#002c99">存储q程</font></a>Q的优化的项目开发h员,Ҏ(gu)据库有浓厚兴的人?  <br /><br />  二、介l:(x)在数据库的开发过E中Q经怼(x)遇到复杂的业务逻辑和对数据库的操作Q这个时候就?x)用SP来封装数据库操作。如果项目的SP较多Q书写又没有一定的规范Q将?x)?jing)响以后的pȝl护困难和大SP逻辑的难以理解,另外如果数据库的数据量大或者项目对SP的性能要求很,׃(x)遇到优化的问题,否则速度有可能很慢,l过亲nl验Q一个经q优化过的SP要比一个性能差的SP的效率甚至高几百倍?  <br /><br />  三、内容:(x)   <br /><br />  1、开发h员如果用到其他库的Table或ViewQ务必在当前库中建立View来实现跨库操作,最好不要直接用“databse.dbo.table_name”,因ؓ(f)sp_depends不能昄?gu)SP所使用的跨库table或viewQ不方便校验。   <br /><br />  2、开发h员在提交SP前,必须已经使用set showplan on分析q查询计划,做过自n的查询优化检查?  <br /><br />  3?a class="bluekey" target="_blank"><font color="#002c99">高程</font></a>序运行效率,优化应用E序Q在SP~写q程中应该注意以下几点:(x)    <br /><br />  a)SQL的用规范:(x) <br /><br />   i. 量避免大事务操作,慎用holdlock子句Q提高系lƈ发能力?<br /><br />   ii. 量避免反复讉K同一张或几张表,其是数据量较大的表Q可以考虑先根据条件提取数据到临时表中Q然后再做连接?<br /><br />   iii. 量避免使用<a class="bluekey" target="_blank"><font color="#002c99">游标</font></a>Q因为游标的效率较差Q如果游标操作的数据过1万行Q那么就应该改写Q如果用了(jin)游标Q就要尽量避免在游标循环中再q行表连接的操作?<br /><br />   iv. 注意where字句写法Q必考虑语句序Q应该根据烦(ch)引顺序、范围大来定条g子句的前后顺序,可能的?a class="bluekey" target="_blank"><font color="#002c99">字段</font></a>序与烦(ch)引顺序相一_(d)范围从大到小?<br /><br />   v. 不要在where子句中的?”左边进行函数、算术运或其他表达式运,否则pȝ可能无法正用烦(ch)引?<br /><br />   vi. 量使用exists代替select count(1)来判断是否存在记录,count函数只有在统计表中所有行数时使用Q而且count(1)比count(*)更有效率?<br /><br />   vii. 量使用?gt;=”,不要使用?gt;”?<br /><br />   viii. 注意一些or子句和union子句之间的替?<br /><br />   ix. 注意表之间连接的数据cdQ避免不同类型数据之间的q接?<br /><br />   x. 注意存储q程中参数和数据cd的关pR?<br /><br />   xi. 注意insert、update操作的数据量Q防止与其他应用冲突。如果数据量过200个数据页面(400kQ,那么pȝ会(x)q行锁升U,锁会(x)升成表U锁?   <br /><br />  b)索引的用规范:(x) <br /><br />   i. 索引的创与应用结合考虑Q徏议大的OLTP表不要超q?个烦(ch)引?<br /><br />   ii. 可能的使用索引字段作ؓ(f)查询条gQ尤其是聚簇索引Q必要时可以通过index index_name来强制指定烦(ch)?<br /><br />   iii. 避免对大表查询时q行table scanQ必要时考虑新徏索引?<br /><br />   iv. 在用烦(ch)引字D作为条件时Q如果该索引是联合烦(ch)引,那么必须使用到该索引中的W一个字D作为条件时才能保证pȝ使用该烦(ch)引,否则该烦(ch)引将不会(x)被用?<br /><br />   v. 要注意烦(ch)引的l护Q周期性重建烦(ch)引,重新~译存储q程。   <br /><br />  c)tempdb的用规范:(x) <br /><br />   i. 量避免使用distinct、order by、group by、having、join、cumputeQ因些语句会(x)加重tempdb的负担?<br /><br />   ii. 避免频繁创徏和删除(f)时表Q减系l表资源的消耗?<br /><br />   iii. 在新Z(f)时表Ӟ如果一ơ性插入数据量很大Q那么可以用select into代替create tableQ避免logQ提高速度Q如果数据量不大Qؓ(f)?jin)缓和系l表的资源,先create tableQ然后insert?<br /><br />   iv. 如果临时表的数据量较大,需要徏立烦(ch)引,那么应该创Z(f)时表和徏立烦(ch)引的q程攑֜单独一个子存储q程中,q样才能保证pȝ能够很好的用到该(f)时表的烦(ch)引?<br /><br />    v. 如果使用C(jin)临时表,在存储过E的最后务必将所有的临时表显式删除,先truncate tableQ然后drop tableQ这样可以避免系l表的较长时间锁定?<br /><br />    vi. 慎用大的临时表与其他大表的连接查询和修改Q减低系l表负担Q因U操作会(x)在一条语句中多次使用tempdb的系l表。   <br />  d)合理的算法用:(x)    <br /><br />  Ҏ(gu)上面已提到的SQL优化技术和ASE Tuning手册中的SQL优化内容,l合实际应用,采用多种法q行比较,以获得消耗资源最、效率最高的Ҏ(gu)。具体可用ASE调优命o(h)Qset statistics io on, set statistics time on , set showplan on {?br /><br />from: <a >http://dev.yesky.com/251/2099251.shtml</a><img src ="http://m.tkk7.com/weidagang2046/aggbug/62873.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/weidagang2046/" target="_blank">weidagang2046</a> 2006-08-10 22:33 <a href="http://m.tkk7.com/weidagang2046/articles/62873.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>优化SQL Server索引的小技?/title><link>http://m.tkk7.com/weidagang2046/articles/62872.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Thu, 10 Aug 2006 14:32:00 GMT</pubDate><guid>http://m.tkk7.com/weidagang2046/articles/62872.html</guid><wfw:comment>http://m.tkk7.com/weidagang2046/comments/62872.html</wfw:comment><comments>http://m.tkk7.com/weidagang2046/articles/62872.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/weidagang2046/comments/commentRss/62872.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/weidagang2046/services/trackbacks/62872.html</trackback:ping><description><![CDATA[SQL Server中有几个可以让你(g)、调整和优化SQL Server性能的工兗在本文中,我将说明如何用SQL Server的工h优化数据库烦(ch)引的使用Q本文还涉及(qing)到有关烦(ch)引的一般性知识?br /><br /><font size="2"><strong>关于索引的常?/strong></font><br /><br /><p>影响到数据库性能的最大因素就是烦(ch)引。由于该问题的复杂性,我只可能单的谈谈q个问题Q不q关于这斚w的问题,目前有好几本不错的书c可供你参阅。我在这里只讨论两种SQL Server索引Q即clustered索引和nonclustered索引。当考察建立什么类型的索引Ӟ你应当考虑数据cd和保存这些数据的column。同P你也必须考虑数据库可能用到的查询cd以及(qing)使用的最为频J的查询cd?/p><h5>索引的类?/h5><p>如果column保存?jin)高度相关的数据Qƈ且常常被序讉KӞ最好用clustered索引Q这是因为如果用clustered索引QSQL Server?x)在物理上按升序Q默认)(j)或者降序重排数据列Q这样就可以q速的扑ֈ被查询的数据。同P在搜L制在一定范围内的情况下Q对q些column也最好用clustered索引。这是因为由于物理上重排数据Q每个表g只有一个clustered索引?/p><p>与上面情늛反,如果columns包含的数据相x较差,你可以用nonculstered索引。你可以在一个表g使用高达249个nonclustered索引——尽我惌不出实际应用场合?x)用的上q么多烦(ch)引?/p><p>当表g用主关键字(primary keysQ,默认情况下SQL Server?x)自动对包含该关键字的column(s)建立一个独有的cluster索引。很昄Q对q些column(s)建立独有索引意味着d键字的唯一性。当建立外关键字Qforeign keyQ关pLQ如果你打算频繁使用它,那么在外关键字cloumn上徏立nonclustered索引不失Z个好的方法。如果表格有clustered索引Q那么它用一个链表来l护数据之间的关系。相反,如果表格没有clustered索引QSQL Server在一个堆栈中保存数据c(din)?/p><h5>数据?/h5><p>当烦(ch)引徏立v来的时候,SQLServer徏立数据页QdatapageQ,数据|用以加速搜索的指针。当索引建立h的时候,其对应的填充因子也即被设|。设|填充因子的目的是ؓ(f)?jin)指C索引中数据页的百分比。随着旉的推U,数据库的更新?x)消耗掉已有的空闲空_(d)q就?x)导致页被拆分。页拆分的后果是降低?jin)?ch)引的性能Q因而用该索引的查询会(x)D数据存储的支ȝ。当建立一个烦(ch)引时Q该索引的填充因子即被设|好?jin),因此填充因子不能动态维护?/p><p>Z(jin)更新数据中的填充因子,我们可以停止旧有索引q建烦(ch)引,q新设|填充因子(注意Q这媄(jing)响到当前数据库的q行Q在重要场合误}慎用)(j)?i>DBCC INDEXDEFRAG</i>?i>DBCC DBREINDEX</i>是清除clustered和nonculstered索引片的两个命令?i>INDEXDEFRAG</i>是一U在U操作(也就是说Q它不会(x)d其它表格动作Q如查询Q,?i>DBREINDEX</i>则在物理上重建烦(ch)引。在l大多数情况下,重徏索引可以更好的消除碎片,但是q个优点是以d当前发生在该索引所在表g其它动作Zh取来得。当出现较大的碎片烦(ch)引时Q?i>INDEXDEFRAG</i>?x)花上一D|较长的时_(d)q是因ؓ(f)该命令的q行是基于小的交互块Qtransactional blockQ?/p><h5>填充因子</h5><p>当你执行上述措施中的M一个,数据库引擎可以更有效的返回编入烦(ch)引的数据。关于填充因子(fillfactorQ话题已l超Z(jin)本文的范_(d)不过我还是提醒你需要注意那些打用填充因子徏立烦(ch)引的表格?/p><p>在执行查询时QSQL Server动态选择使用哪个索引。ؓ(f)此,SQL ServerҎ(gu)每个索引上分布在该关键字上的l计量来军_使用哪个索引。值得注意的是Q经q日常的数据库活动(如插入、删除和更新表格Q,SQL Server用到的这些统计量可能已经“过期”了(jin)Q需要更新。你可以通过执行<i>DBCC SHOWCONTIG</i>来查看统计量的状态。当你认为统计量已经“过期”时Q你可以执行该表格的<i>UPDATE STATISTICS</i>命o(h)Q这样SQL Server刷C(jin)关于该烦(ch)引的信息?jin)?/p><h5>建立数据库维护计?/h5><p>SQL Server提供?jin)一U简化ƈ自动l护数据库的工具。这个称之ؓ(f)数据库维护计划向|Database Maintenance Plan Wizard QDMPWQ的工具也包括了(jin)对烦(ch)引的优化。如果你q行q个向导Q你?x)看到关于数据库中关于?ch)引的l计量,q些l计量作为日志工作ƈ定时更新Q这样就减轻?jin)手工重建?ch)引所带来的工作量。如果你不想自动定期h索引l计量,你还可以在DMPW中选择重新l织数据和数据页Q这停止旧有烦(ch)引ƈ按特定的填充因子重徏索引?br /><br />from: <a >http://www.zdnet.com.cn/developer/database/story/0,3800066906,39109102,00.htm</a></p><img src ="http://m.tkk7.com/weidagang2046/aggbug/62872.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/weidagang2046/" target="_blank">weidagang2046</a> 2006-08-10 22:32 <a href="http://m.tkk7.com/weidagang2046/articles/62872.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>“用L(fng)录失败。原因:(x)未与信Q SQL Server q接相关联”的解决Ҏ(gu)http://m.tkk7.com/weidagang2046/articles/62838.htmlweidagang2046weidagang2046Thu, 10 Aug 2006 11:49:00 GMThttp://m.tkk7.com/weidagang2046/articles/62838.htmlhttp://m.tkk7.com/weidagang2046/comments/62838.htmlhttp://m.tkk7.com/weidagang2046/articles/62838.html#Feedback0http://m.tkk7.com/weidagang2046/comments/commentRss/62838.htmlhttp://m.tkk7.com/weidagang2046/services/trackbacks/62838.html建好SQL数据库,讄好了(jin)用户名与密码Q连接也好了(jin)Q却出现?jin)上q问题, 原困是未讄SQL SERVERd认证模式为؜合认证模式,因ؓ(f)SQL SERVER默认安装后认证模式ؓ(f)WINDOWS认证模式Q从而导致出错?/p>

解决Ҏ(gu)Q?/p>

  1. 启动SQLSERVER企业理器,选择要进行认证模式设|的服务器。右击该服务器,在弹?gu)单中选择属性,SQL SERVER弹出属性对话框

sql1

2. 在属性对话框中选择安全性选项Q在w䆾验证处选择“SQL Server和W(xu)indows”,然后定?br />
sql2

from: http://www.lunji.com/faq/login_error.htm



weidagang2046 2006-08-10 19:49 发表评论
]]>
SQL Server 2000的安全配|?/title><link>http://m.tkk7.com/weidagang2046/articles/62729.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Thu, 10 Aug 2006 02:21:00 GMT</pubDate><guid>http://m.tkk7.com/weidagang2046/articles/62729.html</guid><wfw:comment>http://m.tkk7.com/weidagang2046/comments/62729.html</wfw:comment><comments>http://m.tkk7.com/weidagang2046/articles/62729.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/weidagang2046/comments/commentRss/62729.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/weidagang2046/services/trackbacks/62729.html</trackback:ping><description><![CDATA[SQL Server 2000的安全配|在q行SQL Server 2000数据库的安全配置之前Q首先你必须Ҏ(gu)作系l进行安全配|,保证你的操作pȝ处于安全状态。然后对你要使用的操作数据库软gQ程序)(j)q行必要的安全审核,比如对ASP、PHP{脚本,q是很多Z数据库的WEB应用常出现的安全隐?zhn)Q对于脚本主要是一个过滤问题,需要过滤一些类?, ?; @ / {字W,防止破坏者构造恶意的SQL语句。接着Q安装SQL Server2000后请打上补丁sp1以及(qing)最新的sp2?br /><br />  下蝲地址是:(x)<a ><font color="#666666">http://www.microsoft.com/sql/downloads/2000/sp1.asp</font></a> <br />?<a ><font color="#666666">http://www.microsoft.com/sql/downloads/2000/sp2.asp</font></a><br />在做完上面三步基之后Q我们再来讨论SQL Server的安全配|?br /><br />  <strong>1、用安全的密码{略</strong><br /><br />  我们把密码策略摆在所有安全配|的W一步,h意,很多数据库帐L(fng)密码q于单,q跟pȝ密码q于单是一个道理。对于sa更应该注意,同时不要让sa帐号的密码写于应用程序或者脚本中。健壮的密码是安全的W一步!SQL Server2000安装的时候,如果是用؜合模式,那么需要输入sa的密码,除非你确认必M用空密码。这比以前的版本有所改进。同时养成定期修改密码的好习(fn)惯。数据库理员应该定期查看是否有不符合密码要求的帐号?br /><br />  比如使用下面的SQL语句Q?br />  Use master<br />  Select name,Password from syslogins where password is null<br /><br />  <strong>2、用安全的帐号{略</strong><br /><br />  ׃SQL Server不能更改sa用户名称Q也不能删除q个用户Q所以,我们必须对这个帐可行最强的保护Q当?dng)包括使用一个非常强壮的密码Q最好不要在数据库应用中使用sa帐号Q只有当没有其它Ҏ(gu)d?SQL Server 实例Q例如,当其它系l管理员不可用或忘记?jin)密码?j)时才使用 sa。徏议数据库理员新建立个拥有与sa一h限的用户来管理数据库。安全的帐号{略q包括不要让理员权限的帐号泛滥?br /><br />  SQL Server的认证模式有Windowsw䆾认证和؜合n份认证两U。如果数据库理员不希望操作pȝ理员来通过操作pȝ登陆来接触数据库的话Q可以在帐号理中把pȝ帐号“BUILTIN\Administrators”删除。不q这样做的结果是一旦sa帐号忘记密码的话Q就没有办法来恢复了(jin)。很多主Z用数据库应用只是用来做查询、修改等单功能的Q请Ҏ(gu)实际需要分配帐Pq赋予仅仅能够满_用要求和需要的权限。比如,只要查询功能的,那么׃用一个简单的public帐号能够select可以了(jin)?br /><br />  <strong>3、加强数据库日志的记?/strong><br /><br />  审核数据库登录事件的“失败和成功”,在实例属性中选择“安全性”,其中的审核U别选定为全部,q样在数据库pȝ和操作系l日志里面,pl记录了(jin)所有帐L(fng)d事g。请定期查看SQL Server日志(g)查是否有可疑的登录事件发生,或者用DOS命o(h)。findstr /C:"d" d:\Microsoft SQL Server\MSSQL\LOG\*.*<br /><br />  <strong>4、管理扩展存储过E?/strong><br /><br />  对存储过E进行大手术Qƈ且对帐号调用扩展存储q程的权限要慎重。其实在多数应用中根本用不到多少pȝ的存储过E,而SQL Server的这么多pȝ存储q程只是用来适应q大用户需求的Q所以请删除不必要的存储q程Q因为有些系l的存储q程能很Ҏ(gu)地被人利用v来提升权限或q行破坏。如果你不需要扩展存储过Exp_cmdshellh它去掉。用这个SQL语句Q?<br />use master <br />sp_dropextendedproc 'xp_cmdshell'<br />xp_cmdshell是进入操作系l的最x径,是数据库留给操作pȝ的一个大后门。如果你需要这个存储过E,L(fng)q个语句也可以恢复过来?br />sp_addextendedproc 'xp_cmdshell', 'xpsql70.dll'<br />如果你不需要请丢弃OLE自动存储q程Q会(x)造成理器中的某些特征不能用)(j)Q?br />q些q程包括如下Q?<br />Sp_OACreate Sp_OADestroy Sp_OAGetErrorInfo Sp_OAGetProperty<br />Sp_OAMethod Sp_OASetProperty Sp_OAStop <br />L不需要的注册表访问的存储q程Q注册表存储q程甚至能够d操作pȝ理员的密码来,如下Q?<br />Xp_regaddmultistring Xp_regdeletekey Xp_regdeletevalue <br />Xp_regenumvalues Xp_regread Xp_regremovemultistring <br />Xp_regwrite<br />q有一些其他的扩展存储q程Q你也最好检查检查。在处理存储q程的时候,L(fng)认一下,避免造成Ҏ(gu)据库或应用程序的伤害?br /><br />  <strong>5、用协议加?/strong><br /><br />  SQL Server 2000使用的Tabular Data Stream协议来进行网l数据交换,如果不加密的话,所有的|络传输都是明文的,包括密码、数据库内容{等Q这是一个很大的安全威胁。能被h在网l中截获C们需要的东西Q包括数据库帐号和密码。所以,在条件容许情况下Q最好用SSL来加密协议,当然Q你需要一个证书来支持?br /><br />  <strong>6、不要让人随便探到你的TCP/IP端口</strong><br /><br />  默认情况下,SQL Server使用1433端口监听Q很多h都说SQL Server配置的时候要把这个端口改变,q样别h׃能很Ҏ(gu)地知道用的什么端口了(jin)。可惜,通过微Y未公开?434端口的UDP探测可以很容易知道SQL Server使用的什么TCP/IP端口?jin)。不q微软还是考虑C(jin)q个问题Q毕竟公开而且开攄端口?x)引起不必要的麻烦(ch)。在实例属性中选择TCP/IP协议的属性。选择隐藏 SQL Server 实例。如果隐藏了(jin) SQL Server 实例Q则禁止对试图枚D|络上现有的 SQL Server 实例的客L(fng)所发出的广播作出响应。这P别h׃能用1434来探你的TCP/IP端口?jin)(除非用Port ScanQ?br /><br />  <strong>7、修改TCP/IP使用的端?/strong><br /><br />  请在上一步配|的基础上,更改原默认的1433端口。在实例属性中选择|络配置中的TCP/IP协议的属性,TCP/IP使用的默认端口变为其他端?<br /><br />  <strong>9、拒l来?434端口的探?br /></strong><br />  ׃1434端口探测没有限制Q能够被别h探测C些数据库信息Q而且q可能遭到DOSd让数据库服务器的CPU负荷增大Q所以对Windows 2000操作pȝ来说Q在IPSecqo(h)拒绝?434端口的UDP通讯Q可以尽可能地隐藏你的SQL Server?br /><br />  <strong>10、对|络q接q行IP限制</strong><br /><br />  SQL Server 2000数据库系l本w没有提供网l连接的安全解决办法Q但是Windows 2000提供?jin)这L(fng)安全机制。用操作系l自qIPSec可以实现IP数据包的安全性。请对IPq接q行限制Q只保证自己的IP能够讉KQ也拒绝其他IPq行的端口连接,把来自网l上的安全威胁进行有效的控制。关于IPSec的用请参看Q?a ><font color="#666666">http://www.microsoft.com/china/technet/security/ipsecloc.asp</font></a><br /><br />  上面主要介绍的一些SQL Server的安全配|,l过以上的配|,可以让SQL Server本n具备_的安全防范能力。当?dng)更主要的q是要加强内部的安全控制和管理员的安全培训,而且安全性问题是一个长期的解决q程Q还需要以后进行更多的安全l护?br /><br />from: <a >http://vod.sjtu.edu.cn/help/Article_Show.asp?ArticleID=202</a><img src ="http://m.tkk7.com/weidagang2046/aggbug/62729.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/weidagang2046/" target="_blank">weidagang2046</a> 2006-08-10 10:21 <a href="http://m.tkk7.com/weidagang2046/articles/62729.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于 PostgreSQL 备䆾恢复的心(j)?/title><link>http://m.tkk7.com/weidagang2046/articles/3455.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Tue, 19 Apr 2005 05:39:00 GMT</pubDate><guid>http://m.tkk7.com/weidagang2046/articles/3455.html</guid><wfw:comment>http://m.tkk7.com/weidagang2046/comments/3455.html</wfw:comment><comments>http://m.tkk7.com/weidagang2046/articles/3455.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/weidagang2046/comments/commentRss/3455.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/weidagang2046/services/trackbacks/3455.html</trackback:ping><description><![CDATA[<FONT size=2>q段旉?PostgreSQL 的备份恢复进行了(jin)一些研I? 有一些心(j)得和大家分n一?<BR><BR>我们知道, PostgreSQL 拥有 WAL(预写式日? 已经有一D|间了(jin).<BR>WAL 的一个重要好处就是能在系l崩?数据库崩溃甚x作系l崩?的情况下,<BR>仍然能够保证数据的安? 理想情况下就是恢复到pȝ崩溃前一ȝ一致状?<BR><BR>WAL 是如何实现这一点的? q里单探讨一?<BR><BR>PostgreSQL 数据目录中包括一个子目录?pg_xlog, q里包含一些很 "整齐" 的文?BR>(文g名全都是16q制的数, 大小都是16MB(默认情况?). <BR>q些文g是联机重做日志文? 也就是很?PostgreSQL 文档中说?XLog.<BR>预写式日志就表现在对 XLog 操作? 当一个事务要提交, 已被修改的数?BR>必须先被写到(严格来说应该是追??XLog ? 事务才能标识?"已提?.<BR>q样, qL据文件在崩溃中已l包含不完整的数据了(jin), 仍然可以通过下面<BR>的方法恢复到一致状?<BR><BR>1 扑ֈ前一个一致的数据库状态点(q称为CheckPoint)<BR>2 ?XLog 以快q的方式重新施加C数据文g? 直到崩溃前的时刻.<BR><BR>从这个角度来? PostgreSQL 已经做得非常好了(jin), 但仍然有一些问?<BR>比如, 如果介质(盘)发生故障, 整个数据库文? 包括L据文件和日志<BR>都不能读? 又该怎么办呢?<BR><BR>目前, 我们只能定时通过 pg_dump {工h整个数据?dump 下来, 或?BR>关闭数据? 数据目录整个复制到另外的地? <BR>然后使用q样的备份来恢复׃质故障引L(fng)数据库灾?<BR>很显? q不能满x们的要求, 通常, 我们都不可能以非帔R<BR>的频率进?pg_dump. 一旦发生灾? 最多恢复到上一ơ执?pg_dump 的时M(jin).<BR><BR>没有更好的办法了(jin)?<BR><BR>如果我们能对数据库的做不间断的增量备? 不就可以到达我们的目的了(jin)?<BR>q个x到是? 可怎么捕捉Ҏ(gu)据文件做的修?同时q不要忘C务的原子?? <BR>Ҏ(gu)据文件的修改是分布于整个数据文g各处? 很难对它们进?BR>所? q个Ҏ(gu)是不现实?<BR><BR>现实的方法还是要通过 WAL pȝ来实? h意前面我们已l讨? ?XLog <BR>的写实际上是q加. q一点得要增量备䆾 XLog 成ؓ(f)可能.<BR>目前, PostgreSQL Z(jin)能限?XLog 的大? 采用?jin)多个?也就是多个文?的方?<BR>循环利用盘I间 -- 当写满前一?XLog 文g, ׃生一个新? q且?BR>文g名代?XLog 的编? 同时, 如果可能, 删除q期?XLog 文g.<BR>如果我们能在 PostgreSQL 删除q期?XLog 之前它们复制到另外一个磁盘甚臛_?BR>计算? 不就能够实现增量备䆾日志?jin)? <BR>当灾隑֏生的时? 可以在一个完整备份的基础? q箋施加备䆾?XLog q行<BR>redu, 直至恢复到最后一ơ归?复制到其他目录或计算?的日?<BR><BR>实际? q种Ҏ(gu)也正?Oracle 数据库的归档模式所采用的方?<BR><BR>下面q个实验可以加深理解<BR><BR>1 初始化数据库目录<BR><BR>$ initdb -D db<BR><BR>2 创徏数据?BR><BR>$ pg_ctl -D db start<BR>$ createdb test<BR>$ psql test<BR>test=# create table t(a int);<BR>test=# insert into t values(1);<BR>test=# insert into t values(2);<BR>test=# insert into t values(3);<BR>test=# \q<BR><BR><BR>3 全备份数据库: 在不关闭数据?也就是说, 不要q行 pg_ctl -D db stop)<BR>的情况下复制数据库目? 注意, q里采用?jin)一U非常规手段, 仅仅是ؓ(f)?jin)实? <BR>不要在正式应用中使用. 目的是ؓ(f)?jin)让来的恢复能自动开?<BR><BR>$ cp -a db db.backup<BR><BR>4 l箋修改数据?BR><BR>$ psql test<BR>test=# insert into t values(100);<BR>test=# insert into t values(200);<BR>test=# insert into t values(300);<BR>test=# \q<BR><BR>5 备䆾日志(XLog)文g (׃修改量很? 实际上只有一个日志文?<BR><BR>$ mkdir pg_xlog<BR>$ cp db/pg_xlog/* pg_xlog<BR><BR>6 模拟N<BR><BR>$ pg_ctl -D db stop<BR>$ rm -rf db # 可以不用真的删除, 只是认ؓ(f)它已l不存在?BR><BR>7 q行N恢复<BR><BR>$ cp -a db.backup db.restore<BR>$ cp -f pg_xlog/* db.restore/pg_xlog<BR>$ postmaster -D db.restore # 没有?pg_ctl 启动, <BR># Z(jin)更清楚看到日?此日志非彼日?输出<BR>LOG: database system was interrupted at 2004-04-15 18:12:47 CST<BR>LOG: checkpoint record is at 0/9B1058<BR>LOG: redo record is at 0/9B1058; undo record is at 0/0; shutdown TRUE<BR>LOG: next transaction ID: 536; next OID: 17142<BR>LOG: database system was not properly shut down; automatic recovery in progress<BR>LOG: redo starts at 0/9B1098<BR>LOG: record with zero length at 0/9D4458<BR>LOG: redo done at 0/9D4434<BR>LOG: database system is ready<BR><BR><BR>$ psql test # 另外开一个控制台<BR>test=# select * from t;<BR>a<BR>-----<BR>1<BR>2<BR>3<BR>100<BR>200<BR>300<BR>(6 rows)<BR><BR>可见, 数据库已l已l恢复了(jin)C(jin)N发生前的一?<BR><BR>当然, q个实验数据量很只产生q复制了(jin)一个日志文? 而且复制的日志文?BR>q是当前正在工作? 和前面描q的不完全一? 更深入的实验大家可以下来?<BR><BR>实际的联机热备䆾(也叫PITR(Point In Time Recovery))q有很多l节, 不过<BR>ȝ来说, PostgreSQL d现联机热备䆾已经很近很近? 也许下一个版本我们就能看?BR>q个令h兴奋的功能了(jin). 我们热切地期待着! <BR><BR>她已lؓ(f)我们做了(jin)q么? 我们能ؓ(f)她做点什么呢? <BR><BR><BR>以上内容仅代表我自己的理? 不正之处敬请指出.<BR><BR>kernel <BR>2004.4.15<BR><BR><BR>转自: </FONT><A ><FONT size=2>http://bbs.pgsqldb.com/index.php?t=msg&th=3739&start=0</FONT></A><img src ="http://m.tkk7.com/weidagang2046/aggbug/3455.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/weidagang2046/" target="_blank">weidagang2046</a> 2005-04-19 13:39 <a href="http://m.tkk7.com/weidagang2046/articles/3455.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在FAT32格式的Win2k下安装Postgresqlhttp://m.tkk7.com/weidagang2046/articles/3435.htmlweidagang2046weidagang2046Tue, 19 Apr 2005 01:26:00 GMThttp://m.tkk7.com/weidagang2046/articles/3435.htmlhttp://m.tkk7.com/weidagang2046/comments/3435.htmlhttp://m.tkk7.com/weidagang2046/articles/3435.html#Feedback0http://m.tkk7.com/weidagang2046/comments/commentRss/3435.htmlhttp://m.tkk7.com/weidagang2046/services/trackbacks/3435.htmlPostgresql在FAT32下的安装和NTFS下有所不同Q下面只讨论FAT32下Postgresql的安装:(x)

(1)  到Postgresql的官方网?A >http://www.postgresql.org/下蝲安装文g?BR>(2)  q行安装E序Q本文假讑֮装\径选C:\pgsqlQdata路径选D:\pgsql\dataQ注意安装过E中不要选install as service?BR>(3)  C:\pgsql\bin加入PATH环境变量?BR>(4)  d用户postgresQ本文假讑֯码ؓ(f)1234?BR>(5)  用postgres帐号初始化数据库集群。可以先注销当前用户再用postgres帐号登陆Q也可以用命令runas /user:postgres cmd切换到postgres帐号Q然后在命o(h)提示W下面输入:(x)initdb -E UNICODE --locale=C -D d:\pgsql\data。注意:(x)要先建立d:\pgsql\data目录?BR>(6)  安装服务Q用Administrator帐号来做Qƈ启动Qpg_ctl register -N PostgreSQL -U postgres -P 1234 -D d:\pgsql\data
(7)  用postgres帐号q行Qcreateuser -a Administrator为数据库d一个超U用P以后的操作都可以用Administrator帐号来完成,不必切换到postgres帐号?/FONT>

weidagang2046 2005-04-19 09:26 发表评论
]]>
վ֩ģ壺 һëƬѿѲ | ѻɫƵ| 츾Ļʮг| ޳߲va| պƬѿ| ޾Ʒ| ޾Ʒ9999þþþ| һ| ޹ŮƷþþþá| ޳aëƬ| Ů˿ƬƵ| Ļһ | ᰡͣѿ| ɫaAV| һ| aƬѹۿƵ| ޸߲| ѹۿ| ޾Ʒ˿þ| Ʒѿþþ㽶| Ļwww˳| ۺa| þþþAV| þþƷƵѿ| þþƷav鶹ѿ | һӰ߹ۿ| ӰԺһҳСƵ߹ۿ | պػɫƬƵ| Ʒ˳վ| һ| ޳?߹ۿ| ҳƵվ | һëƬ߹| һaƬɫëƬ| þùƷ| ղƷBD߹ۿ| Ѻܻƺɫ߹ۿ| 91ֻƷѹۿ| 91޾Ʒһۺϲ| Ʒþ޾þþþûʿ| aëƬȫ|