﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-beautykingdom-随笔分类-Database</title><link>http://www.cppblog.com/beautykingdom/category/12296.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 05 Sep 2011 09:36:52 GMT</lastBuildDate><pubDate>Mon, 05 Sep 2011 09:36:52 GMT</pubDate><ttl>60</ttl><item><title>MySQL索引背后的数据结构及算法原理</title><link>http://www.cppblog.com/beautykingdom/archive/2011/09/05/155112.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Mon, 05 Sep 2011 02:36:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2011/09/05/155112.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/155112.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2011/09/05/155112.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/155112.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/155112.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: from:http://www.cnblogs.com/leoo2sk/archive/2011/07/10/mysql-index.html#nav-2-2在编程领域有一句人尽皆知的法则&#8220;程序 = 数据结构 + 算法&#8221;，我个人是不太赞同这句话（因为我觉得程序不仅仅是数据结构加算法），但是在日常的学习和工作中我确认深深感受到数据结构和算法的重要性，很多东西，如果你愿意稍稍往...&nbsp;&nbsp;<a href='http://www.cppblog.com/beautykingdom/archive/2011/09/05/155112.html'>阅读全文</a><img src ="http://www.cppblog.com/beautykingdom/aggbug/155112.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2011-09-05 10:36 <a href="http://www.cppblog.com/beautykingdom/archive/2011/09/05/155112.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>What are the difference between DDL, DML and DCL commands?&lt;转载&gt;</title><link>http://www.cppblog.com/beautykingdom/archive/2011/08/19/153837.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Fri, 19 Aug 2011 02:26:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2011/08/19/153837.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/153837.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2011/08/19/153837.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/153837.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/153837.html</trackback:ping><description><![CDATA[<div>from:<br /><a href="http://www.orafaq.com/faq/what_are_the_difference_between_ddl_dml_and_dcl_commands">http://www.orafaq.com/faq/what_are_the_difference_between_ddl_dml_and_dcl_commands</a><br /><br /><span style="widows: 2; text-transform: none; text-indent: 0px; letter-spacing: normal; border-collapse: separate; font: 16px 'Times New Roman'; white-space: normal; orphans: 2; color: rgb(0,0,0); word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"><span style="text-align: left; line-height: 19px; border-collapse: collapse; font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51); font-size: 13px" class="Apple-style-span"> 
<h3 style="margin: 0px; font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(102,153,204); font-size: 1.5em"><a name="DDL">DDL</a></h3><br /><span style="font-weight: bold">Data Definition Language</span><span class="Apple-converted-space">&nbsp;</span>(DDL) statements are used to define the database structure or schema. Some examples: 
<p style="padding-bottom: 0px; margin: 0px 0px 1.2em; padding-left: 0px; padding-right: 0px; padding-top: 0px"></p>
<ul style="list-style-type: circle; font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)" class="bb-list"><li style="font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)">CREATE - to create objects in the database</li><li style="font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)">ALTER - alters the structure of the database</li><li style="font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)">DROP - delete objects from the database</li><li style="font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)">TRUNCATE - remove all records from a table, including all spaces allocated for the records are removed</li><li style="font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)">COMMENT - add comments to the data dictionary</li><li style="font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)">RENAME - rename an object</li></ul>
<p style="padding-bottom: 0px; margin: 0px 0px 1.2em; padding-left: 0px; padding-right: 0px; padding-top: 0px"></p>
<h3 style="margin: 0px; font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(102,153,204); font-size: 1.5em"><a name="DML">DML</a></h3><br /><span style="font-weight: bold">Data Manipulation Language</span><span class="Apple-converted-space">&nbsp;</span>(DML) statements are used for managing data within schema objects. Some examples: 
<p style="padding-bottom: 0px; margin: 0px 0px 1.2em; padding-left: 0px; padding-right: 0px; padding-top: 0px"></p>
<ul style="list-style-type: circle; font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)" class="bb-list"><li style="font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)">SELECT - retrieve data from the a database</li><li style="font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)">INSERT - insert data into a table</li><li style="font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)">UPDATE - updates existing data within a table</li><li style="font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)">DELETE - deletes all records from a table, the space for the records remain</li><li style="font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)">MERGE - UPSERT operation (insert or update)</li><li style="font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)">CALL - call a PL/SQL or Java subprogram</li><li style="font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)">EXPLAIN PLAN - explain access path to data</li><li style="font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)">LOCK TABLE - control concurrency</li></ul>
<p style="padding-bottom: 0px; margin: 0px 0px 1.2em; padding-left: 0px; padding-right: 0px; padding-top: 0px"></p>
<h3 style="margin: 0px; font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(102,153,204); font-size: 1.5em"><a name="DCL">DCL</a></h3><br /><span style="font-weight: bold">Data Control Language</span><span class="Apple-converted-space">&nbsp;</span>(DCL) statements. Some examples: 
<p style="padding-bottom: 0px; margin: 0px 0px 1.2em; padding-left: 0px; padding-right: 0px; padding-top: 0px"></p>
<ul style="list-style-type: circle; font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)" class="bb-list"><li style="font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)">GRANT - gives user's access privileges to database</li><li style="font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)">REVOKE - withdraw access privileges given with the GRANT command</li></ul>
<p style="padding-bottom: 0px; margin: 0px 0px 1.2em; padding-left: 0px; padding-right: 0px; padding-top: 0px"></p>
<h3 style="margin: 0px; font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(102,153,204); font-size: 1.5em"><a name="TCL">TCL</a></h3><br /><span style="font-weight: bold">Transaction Control</span><span class="Apple-converted-space">&nbsp;</span>(TCL) statements are used to manage the changes made by DML statements. It allows statements to be grouped together into logical transactions. 
<p style="padding-bottom: 0px; margin: 0px 0px 1.2em; padding-left: 0px; padding-right: 0px; padding-top: 0px"></p>
<ul style="list-style-type: circle; font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)" class="bb-list"><li style="font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)">COMMIT - save work done</li><li style="font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)">SAVEPOINT - identify a point in a transaction to which you can later roll back</li><li style="font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)">ROLLBACK - restore database to original since the last COMMIT</li><li style="font-family: 'Trebuchet MS', Geneva, Arial, Helvetica, SunSans-Regular, Verdana, sans-serif; color: rgb(51,51,51)">SET TRANSACTION - Change transaction options like isolation level and what rollback segment to use</li></ul></span></span></div><img src ="http://www.cppblog.com/beautykingdom/aggbug/153837.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2011-08-19 10:26 <a href="http://www.cppblog.com/beautykingdom/archive/2011/08/19/153837.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>查询优化</title><link>http://www.cppblog.com/beautykingdom/archive/2009/11/24/101826.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Tue, 24 Nov 2009 09:04:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2009/11/24/101826.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/101826.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2009/11/24/101826.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/101826.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/101826.html</trackback:ping><description><![CDATA[<span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: rgb(0,0,0); WORD-SPACING: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class=Apple-style-span><span style="TEXT-ALIGN: left; LINE-HEIGHT: 21px; FONT-FAMILY: Arial, Helvetica, sans-serif; COLOR: rgb(51,51,51); FONT-SIZE: 12px" class=Apple-style-span>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all"><a style="LINE-HEIGHT: normal !important; COLOR: rgb(51,51,51); WORD-BREAK: break-all; TEXT-DECORATION: underline" onclick="javascript:tagshow(event, '%CA%FD%BE%DD%BF%E2');" href="javascript:;" target=_self><u style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">数据库</strong></u></a>系统是<a style="LINE-HEIGHT: normal !important; COLOR: rgb(51,51,51); WORD-BREAK: break-all; TEXT-DECORATION: underline" onclick="javascript:tagshow(event, '%B9%DC%C0%ED');" href="javascript:;" target=_self><u style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">管理</strong></u></a>信息系统的核心，基于数据库的联机事务处理（OLTP）以及联机分析处理(OLAP)是银行、企业、政府等部门最为重要的计算机应 用之一。从大多数系统的应用实例来看，查询操作在各种数据库操作中所占据的比重最大，而查询操作所基于的SELECT语句在<a style="LINE-HEIGHT: normal !important; COLOR: rgb(51,51,51); WORD-BREAK: break-all; TEXT-DECORATION: underline" onclick="javascript:tagshow(event, 'SQL');" href="javascript:;" target=_self><u style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">SQL</strong></u></a>语句中又是代价最大的语 句。举例来说，如果数据的量积累到一定的程度，比如一个银行的账户数据库表信息积累到上百万甚至上千万条记录，全表扫描一次往往需要数十分钟，甚至数小 时。如果采用比全表扫描更好的查询策略，往往可以使查询时间降为几分钟，由此可见查询优化技术的重要性。</p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all">笔者在应用项目的实施中发现，许多程序员在利用一些前端数据库<a style="LINE-HEIGHT: normal !important; COLOR: rgb(51,51,51); WORD-BREAK: break-all; TEXT-DECORATION: underline" onclick="javascript:tagshow(event, '%BF%AA%B7%A2%B9%A4%BE%DF');" href="javascript:;" target=_self><u style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">开发工具</strong></u></a>（如PowerBuilder、Delphi等）开发数据库应用程序时，只注 重用户界面的华丽，并不重视查询语句的效率问题，导致所开发出来的应用系统效率低下，资源浪费严重。因此，如何设计高效合理的查询语句就显得非常重要。本 文以应用实例为基础，结合数据库理论，介绍查询优化技术在现实系统中的运用。</p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">分析问题</strong></p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all">许多程序员认为查询优化是DBMS（数据库管理系统）的任务，与程序员所编写的SQL语句关系不大，这是错误的。一个好的查询计划往往可以使程序性 能提高数十倍。查询计划是用户所提交的SQL语句的集合，查询规划是经过优化处理之后所产生的语句集合。DBMS处理查询计划的过程是这样的：在做完查询 语句的词法、语法检查之后，将语句提交给DBMS的查询优化器，优化器做完代数优化和存取路径的优化之后，由预编译模块对语句进行处理并生成查询规划，然 后在合适的时间提交给系统处理执行，最后将执行结果返回给用户。在实际的数据库产品(如Oracle、Sybase等)的高版本中都是采用基于代价的优化 方法，这种优化能根据从系统字典表所得到的信息来估计不同的查询规划的代价，然后选择一个较优的规划。虽然现在的数据库产品在查询优化方面已经做得越来越 好，但由用户提交的SQL语句是系统优化的基础，很难设想一个原本糟糕的查询计划经过系统的优化之后会变得高效，因此用户所写语句的优劣至关重要。系统所 做查询优化我们暂不讨论，下面重点说明改善用户查询计划的解决<a style="LINE-HEIGHT: normal !important; COLOR: rgb(51,51,51); WORD-BREAK: break-all; TEXT-DECORATION: underline" onclick="javascript:tagshow(event, '%B7%BD%B0%B8');" href="javascript:;" target=_self><u style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">方案</strong></u></a>。<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">解决问题</strong></p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all">下面以关系数据库系统Informix为例，介绍改善用户查询计划的方法。</p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">1．合理使用索引</strong></p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all">索引是数据库中重要的数据结构，它的根本目的就是为了提高查询效率。现在大多数的数据库产品都采用IBM最先提出的ISAM索引结构。索引的使用要恰到好处，其使用原则如下：</p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all">●在经常进行连接，但是没有指定为外键的列上建立索引，而不经常连接的字段则由优化器自动生成索引。<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">●在频繁进行排序或分组（即进行group by或order by操作）的列上建立索引。<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">●在条件表达式中经常用到的不同值较多的列上建立检索，在不同值少的列上不要建立索引。比如在雇员表的&#8220;性别&#8221;列上只有&#8220;男&#8221;与&#8220;女&#8221;两个不同值，因此就无必要建立索引。如果建立索引不但不会提高查询效率，反而会严重降低更新速度。<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">●如果待排序的列有多个，可以在这些列上建立复合索引（compound index）。<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">● 使用系统工具。如Informix数据库有一个tbcheck工具，可以在可疑的索引上进行检查。在一些数据库服务器上，索引可能失效或者因为频繁操作而 使得读取效率降低，如果一个使用索引的查询不明不白地慢下来，可以试着用tbcheck工具检查索引的完整性，必要时进行修复。另外，当数据库表更新大量 数据后，删除并重建索引可以提高查询速度。</p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">2．避免或简化排序</strong></p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all">应当简化或避免对大型表进行重复的排序。当能够利用索引自动以适当的次序产生输出时，优化器就避免了排序的步骤。以下是一些影响因素：<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">●索引中不包括一个或几个待排序的列；<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">●group by或order by子句中列的次序与索引的次序不一样；<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">●排序的列来自不同的表。<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">为了避免不必要的排序，就要正确地增建索引，合理地合并数据库表（尽管有时可能影响表的规范化，但相对于效率的提高是值得的）。如果排序不可避免，那么应当试图简化它，如缩小排序的列的范围等。</p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">3．消除对大型表行数据的顺序存取</strong></p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all">在嵌套查询中，对表的顺序存取对查询效率可能产生致命的影响。比如采用顺序存取策略，一个嵌套3层的查询，如果每层都查询1000行，那么这个查询 就要查询10亿行数据。避免这种情况的主要方法就是对连接的列进行索引。例如，两个表：学生表（学号、姓名、年龄&#8230;&#8230;）和选课表（学号、课程号、成绩）。 如果两个表要做连接，就要在&#8220;学号&#8221;这个连接字段上建立索引。</p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all">还可以使用并集来避免顺序存取。尽管在所有的检查列上都有索引，但某些形式的where子句强迫优化器使用顺序存取。下面的查询将强迫对orders表执行顺序操作：</p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all">SELECT ＊ FROM orders WHERE (customer_num=104 AND order_num&gt;1001) OR order_num=1008</p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all">虽然在customer_num和order_num上建有索引，但是在上面的语句中优化器还是使用顺序存取路径扫描整个表。因为这个语句要检索的是分离的行的集合，所以应该改为如下语句：<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">SELECT ＊ FROM orders WHERE customer_num=104 AND order_num&gt;1001<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">UNION<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">SELECT ＊ FROM orders WHERE order_num=1008<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">这样就能利用索引路径处理查询。</p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">4．避免相关子查询</strong></p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all">一个列的标签同时在主查询和where子句中的查询中出现，那么很可能当主查询中的列值改变之后，子查询必须重新查询一次。查询嵌套层次越多，效率越低，因此应当尽量避免子查询。如果子查询不可避免，那么要在子查询中过滤掉尽可能多的行。</p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">5．避免困难的正规表达式</strong></p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all">MATCHES和LIKE关键字支持通配符匹配，技术上叫正规表达式。但这种匹配特别耗费时间。例如：SELECT ＊ FROM customer WHERE zipcode LIKE &#8220;98_ _ _&#8221;<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">即使在zipcode字段上建立了索引，在这种情况下也还是采用顺序扫描的方式。如果把语句改为SELECT ＊ FROM customer WHERE zipcode &gt;&#8220;98000&#8221;，在执行查询时就会利用索引来查询，显然会大大提高速度。<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">另外，还要避免非开始的子串。例如语句：SELECT ＊ FROM customer WHERE zipcode[2，3] &gt;&#8220;80&#8221;，在where子句中采用了非开始子串，因而这个语句也不会使用索引。</p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">6．使用临时表加速查询</strong></p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all">把表的一个子集进行排序并创建临时表，有时能加速查询。它有助于避免多重排序操作，而且在其他方面还能简化优化器的工作。例如：<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">SELECT cust.name，rc<a style="LINE-HEIGHT: normal !important; COLOR: rgb(51,51,51); WORD-BREAK: break-all; TEXT-DECORATION: underline" class=Channel_KeyLink href="http://www.3w3w.cn/JiaoCheng/ShowClass.asp?ClassID=263">vb</a>les.balance，&#8230;&#8230;other columns<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">FROM cust，rc<a style="LINE-HEIGHT: normal !important; COLOR: rgb(51,51,51); WORD-BREAK: break-all; TEXT-DECORATION: underline" class=Channel_KeyLink href="http://www.3w3w.cn/JiaoCheng/ShowClass.asp?ClassID=263">vb</a>les<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">WHERE cust.customer_id = rcvlbes.customer_id<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">AND rc<a style="LINE-HEIGHT: normal !important; COLOR: rgb(51,51,51); WORD-BREAK: break-all; TEXT-DECORATION: underline" class=Channel_KeyLink href="http://www.3w3w.cn/JiaoCheng/ShowClass.asp?ClassID=263">vb</a>lls.balance&gt;0<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">AND cust.postcode&gt;&#8220;98000&#8221;<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">ORDER BY cust.name</p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all">如果这个查询要被执行多次而不止一次，可以把所有未付款的客户找出来放在一个临时文件中，并按客户的名字进行排序：<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">SELECT cust.name，rcvbles.balance，&#8230;&#8230;other columns<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">FROM cust，rcvbles<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">WHERE cust.customer_id = rcvlbes.customer_id<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">AND rcvblls.balance&gt;0<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">ORDER BY cust.name<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">INTO TEMP cust_with_balance<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">然后以下面的方式在临时表中查询：<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">SELECT ＊ FROM cust_with_balance<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">WHERE postcode&gt;&#8220;98000&#8221;</p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all">临时表中的行要比主表中的行少，而且物理顺序就是所要求的顺序，减少了磁盘I/O，所以查询工作量可以得到大幅减少。 注意：临时表创建后不会反映主表的修改。在主表中数据频繁修改的情况下，注意不要丢失数据。</p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">7．用排序来取代非顺序存取</strong><br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">非顺序磁盘存取是最慢的操作，表现在磁盘存取臂的来回移动。SQL语句隐藏了这一情况，使得我们在写应用程序时很容易写出要求存取大量非顺序页的查询。<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">有些时候，用数据库的排序能力来替代非顺序的存取能改进查询。</p>
转自：<br><a href="http://space.itpub.net/47598/viewspace-223897"><u><font color=#0000ff>http://space.itpub.net/47598/viewspace-223897</font></u></a></span></span>
<img src ="http://www.cppblog.com/beautykingdom/aggbug/101826.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2009-11-24 17:04 <a href="http://www.cppblog.com/beautykingdom/archive/2009/11/24/101826.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>优化MySQL数据库性能的八大“妙手”</title><link>http://www.cppblog.com/beautykingdom/archive/2009/11/24/101825.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Tue, 24 Nov 2009 09:01:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2009/11/24/101825.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/101825.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2009/11/24/101825.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/101825.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/101825.html</trackback:ping><description><![CDATA[<span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: rgb(0,0,0); WORD-SPACING: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class=Apple-style-span><span style="TEXT-ALIGN: left; LINE-HEIGHT: 21px; FONT-FAMILY: Arial, Helvetica, sans-serif; COLOR: rgb(51,51,51); FONT-SIZE: 12px" class=Apple-style-span>本文探讨了提高MySQL<span class=Apple-converted-space>&nbsp;</span><a style="LINE-HEIGHT: normal; COLOR: rgb(51,51,51); WORD-BREAK: break-all; TEXT-DECORATION: underline" onclick="javascript:tagshow(event, '%CA%FD%BE%DD%BF%E2');" href="javascript:;" target=_self><u style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">数据库</strong></u></a>性能的思路，并从8个方面给出了具体的解决方法。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　<strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">1、选取最适用的字段属性</strong><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　MySQL可以很好的支持大数据量的存取，但是一般说来，数据库中的表越小，在它上面执行的查询也就会越快。因此，在创建表的时候，为了获得更好的性 能，我们可以将表中字段的宽度设得尽可能小。例如，在定义邮政编码这个字段时，如果将其设置为CHAR(255),显然给数据库增加了不必要的空间，甚至 使用VARCHAR这种类型也是多余的，因为CHAR(6)就可以很好的完成任务了。同样的，如果可以的话，我们应该使用MEDIUMINT而不是 BIGIN来定义整型字段。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　另外一个提高效率的方法是在可能的情况下，应该尽量把字段设置为NOT NULL，这样在将来执行查询的时候，数据库不用去比较NULL值。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　对于某些文本字段，例如&#8220;省份&#8221;或者&#8220;性别&#8221;，我们可以将它们定义为ENUM类型。因为在MySQL中，ENUM类型被当作数值型数据来处理，而数值型数据被处理起来的速度要比文本类型快得多。这样，我们又可以提高数据库的性能。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　<strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">2、使用连接（JOIN）来代替子查询(Sub-Queries)</strong><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　MySQL从4.1开始支持<a style="LINE-HEIGHT: normal; COLOR: rgb(51,51,51); WORD-BREAK: break-all; TEXT-DECORATION: underline" onclick="javascript:tagshow(event, 'SQL');" href="javascript:;" target=_self><u style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">SQL</strong></u></a>的子查询。这个技术可以使用SELECT语句来创建一个单列的查询结果，然后把这个结果作为过滤条件用在另一个查询 中。例如，我们要将客户基本信息表中没有任何订单的客户删除掉，就可以利用子查询先从销售信息表中将所有发出订单的客户ID取出来，然后将结果传递给主查 询，如下所示：<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
<table style="LINE-HEIGHT: normal; WORD-BREAK: break-all" border=1 borderColor=#cccccc width="90%" bgColor=#e3e3e3 align=center>
    <tbody style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
        <tr style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">DELETE FROM customerinfo<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">WHERE CustomerID NOT in (SELECT CustomerID FROM salesinfo )</td>
        </tr>
    </tbody>
</table>
<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　使用子查询可以一次性的完成很多逻辑上需要多个步骤才能完成的SQL操作，同时也可以避免事务或者表锁死，并且写起来也很容易。但是，有些情况下，子 查询可以被更有效率的连接（JOIN）.. 替代。例如，假设我们要将所有没有订单记录的用户取出来，可以用下面这个查询完成：<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
<table style="LINE-HEIGHT: normal; WORD-BREAK: break-all" border=1 borderColor=#cccccc width="90%" bgColor=#e3e3e3 align=center>
    <tbody style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
        <tr style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">SELECT * FROM customerinfo<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">WHERE CustomerID NOT in (SELECT CustomerID FROM salesinfo )</td>
        </tr>
    </tbody>
</table>
<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　如果使用连接（JOIN）.. 来完成这个查询工作，速度将会快很多。尤其是当salesinfo表中对CustomerID建有索引的话，性能将会更好，查询如下：<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
<table style="LINE-HEIGHT: normal; WORD-BREAK: break-all" border=1 borderColor=#cccccc width="90%" bgColor=#e3e3e3 align=center>
    <tbody style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
        <tr style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">SELECT * FROM customerinfo<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">LEFT JOIN salesinfoON customerinfo.CustomerID=salesinfo.<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">CustomerID<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">WHERE salesinfo.CustomerID IS NULL</td>
        </tr>
    </tbody>
</table>
<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　连接（JOIN）.. 之所以更有效率一些，是因为 MySQL不需要在内存中创建临时表来完成这个逻辑上的需要两个步骤的查询工作。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　<strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">3、使用联合(UNION)来代替手动创建的临时表</strong><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　MySQL 从 4.0 的版本开始支持 UNION 查询，它可以把需要使用临时表的两条或更多的 SELECT 查询合并的一个查询中。在客户端的查询会话结束的时候，临时表会被自动删除，从而保证数据库整齐、高效。使用 UNION 来创建查询的时候，我们只需要用 UNION作为关键字把多个 SELECT 语句连接起来就可以了，要注意的是所有 SELECT 语句中的字段数目要想同。下面的例子就演示了一个使用 UNION的查询。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
<table style="LINE-HEIGHT: normal; WORD-BREAK: break-all" border=1 borderColor=#cccccc width="90%" bgColor=#e3e3e3 align=center>
    <tbody style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
        <tr style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">SELECT Name, Phone FROM client<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">UNION<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">SELECT Name, BirthDate FROM author<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">UNION<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">SELECT Name, Supplier FROM product</td>
        </tr>
    </tbody>
</table>
<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　<strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">4、事务</strong><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　尽管我们可以使用子查询（Sub-Queries）、连接（JOIN）和联合（UNION）来创建各种各样的查询，但不是所有的数据库操作都可以只用 一条或少数几条SQL语句就可以完成的。更多的时候是需要用到一系列的语句来完成某种工作。但是在这种情况下，当这个语句块中的某一条语句运行出错的时 候，整个语句块的操作就会变得不确定起来。设想一下，要把某个数据同时插入两个相关联的表中，可能会出现这样的情况：第一个表中成功更新后，数据库突然出 现意外状况，造成第二个表中的操作没有完成，这样，就会造成数据的不完整，甚至会破坏数据库中的数据。要避免这种情况，就应该使用事务，它的作用是：要么 语句块中每条语句都操作成功，要么都失败。换句话说，就是可以保持数据库中数据的一致性和完整性。事物以BEGIN 关键字开始，COMMIT关键字结束。在这之间的一条SQL操作失败，那么，ROLLBACK命令就可以把数据库恢复到BEGIN开始之前的状态。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
<table style="LINE-HEIGHT: normal; WORD-BREAK: break-all" border=1 borderColor=#cccccc width="90%" bgColor=#e3e3e3 align=center>
    <tbody style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
        <tr style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">BEGIN;<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">INSERT INTO salesinfo SET CustomerID=14;<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">UPDATE inventory SET Quantity=11<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">WHERE item='book';<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">COMMIT;</td>
        </tr>
    </tbody>
</table>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">　　事务的另一个重要作用是当多个用户同时使用相同的数据源时，它可以利用锁定数据库的方法来为用户提供一种<a style="LINE-HEIGHT: normal !important; COLOR: rgb(51,51,51); WORD-BREAK: break-all; TEXT-DECORATION: underline" onclick="javascript:tagshow(event, '%B0%B2%C8%AB');" href="javascript:;" target=_self><u style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">安全</strong></u></a>的访问方式，这样可以保证用户的操作不被其它的用户所干扰。</p>
<p style="LINE-HEIGHT: 1.8em !important; MARGIN: 10px 0px; WORD-BREAK: break-all">　<strong style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">5、锁定表</strong><br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">　　尽管事务是维护数据库完整性的一个非常好的方法，但却因为它的独占性，有时会影响数据库的性能，尤其是在很大的应用系统中。由于在事务执行的过程中，数据库将会被锁定，因此其它的用户请求只能暂时等待直到该事务结束。如果一个数据库系统只有少数几个用户<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">来使用，事务造成的影响不会成为一个太大的问题；但假设有成千上万的用户同时访问一个数据库系统，例如访问一个电子商务网站，就会产生比较严重的响应延迟。<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all">　　其实，有些情况下我们可以通过锁定表的方法来获得更好的性能。下面的例子就用锁定表的方法来完成前面一个例子中事务的功能。<br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal !important; WORD-BREAK: break-all"></p>
<table style="LINE-HEIGHT: normal; WORD-BREAK: break-all" border=1 borderColor=#cccccc width="90%" bgColor=#e3e3e3 align=center>
    <tbody style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
        <tr style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">LOCK TABLE inventory WRITE<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">SELECT Quantity FROM inventory<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">WHEREItem='book';<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">...<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">UPDATE inventory SET Quantity=11<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">WHEREItem='book';<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">UNLOCK TABLES</td>
        </tr>
    </tbody>
</table>
<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　这里，我们用一个 SELECT 语句取出初始数据，通过一些计算，用 UPDATE 语句将新值更新到表中。包含有 WRITE 关键字的 LOCK TABLE 语句可以保证在 UNLOCK TABLES 命令被执行之前，不会有其它的访问来对 inventory 进行插入、更新或者删除的操作。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　6、使用外键<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　锁定表的方法可以维护数据的完整性，但是它却不能保证数据的关联性。这个时候我们就可以使用外键。例如，外键可以保证每一条销售记录都指向某一个存在 的客户。在这里，外键可以把customerinfo 表中的CustomerID映射到salesinfo表中CustomerID，任何一条没有合法CustomerID的记录都不会被更新或插入到 salesinfo中。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
<table style="LINE-HEIGHT: normal; WORD-BREAK: break-all" border=1 borderColor=#cccccc width="90%" bgColor=#e3e3e3 align=center>
    <tbody style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
        <tr style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">CREATE TABLE customerinfo<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">(<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">CustomerID INT NOT NULL ,<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">PRIMARY KEY ( CustomerID )<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">) TYPE = INNODB;<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">CREATE TABLE salesinfo<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">(<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">SalesID INT NOT NULL,<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">CustomerID INT NOT NULL,<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">PRIMARY KEY(CustomerID, SalesID),<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">FOREIGN KEY (CustomerID) REFERENCES customerinfo<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">(CustomerID) ON DELETECASCADE<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">) TYPE = INNODB;</td>
        </tr>
    </tbody>
</table>
<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　注意例子中的参数&#8220;ON DELETE CASCADE&#8221;。该参数保证当 customerinfo 表中的一条客户记录被删除的时候，salesinfo 表中所有与该客户相关的记录也会被自动删除。如果要在 MySQL 中使用外键，一定要记住在创建表的时候将表的类型定义为事务安全表 InnoDB类型。该类型不是 MySQL 表的默认类型。定义的方法是在 CREATE TABLE 语句中加上 TYPE=INNODB。如例中所示。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　<strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">7、使用索引</strong><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　索引是提高数据库性能的常用方法，它可以令数据库服务器以比没有索引快得多的速度检索特定的行，尤其是在查询语句当中包含有MAX(), MIN()和ORDERBY这些命令的时候，性能提高更为明显。那该对哪些字段建立索引呢？一般说来，索引应建立在那些将用于JOIN, WHERE判断和ORDER BY排序的字段上。尽量不要对数据库中某个含有大量重复的值的字段建立索引。对于一个ENUM类型的字段来说，出现大量重复值是很有可能的情况，例如 customerinfo中的&#8220;province&#8221;.. 字段，在这样的字段上建立索引将不会有什么帮助；相反，还有可能降低数据库的性能。我们在创建表的时候可以同时创建合适的索引，也可以使用ALTER TABLE或CREATE INDEX在以后创建索引。此外，MySQL<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">从版本3.23.23开始支持全文索引和搜索。全文索引在MySQL 中是一个FULLTEXT类型索引，但仅能用于MyISAM 类型的表。对于一个大的数据库，将数据装载到一个没有FULLTEXT索引的表中，然后再使用ALTER TABLE或CREATE INDEX创建索引，将是非常快的。但如果将数据装载到一个已经有FULLTEXT索引的表中，执行过程将会非常慢。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　<strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">8、优化的查询语句</strong><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　绝大多数情况下，使用索引可以提高查询的速度，但如果SQL语句使用不恰当的话，索引将无法发挥它应有的作用。下面是应该注意的几个方面。首先，最好 是在相同类型的字段间进行比较的操作。在MySQL 3.23版之前，这甚至是一个必须的条件。例如不能将一个建有索引的INT字段和BIGINT字段进行比较；但是作为特殊的情况，在CHAR类型的字段和 VARCHAR类型字段的字段大小相同的时候，可以将它们进行比较。其次，在建有索引的字段上尽量不要使用函数进行操作。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　例如，在一个DATE类型的字段上使用YEAE()函数时，将会使索引不能发挥应有的作用。所以，下面的两个查询虽然返回的结果一样，但后者要比前者快得多。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
<table style="LINE-HEIGHT: normal; WORD-BREAK: break-all" border=1 borderColor=#cccccc width="90%" bgColor=#e3e3e3 align=center>
    <tbody style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
        <tr style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">SELECT * FROM order WHERE YEAR(OrderDate)&lt;2001;<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">SELECT * FROM order WHERE OrderDate&lt;"2001-01-01";</td>
        </tr>
    </tbody>
</table>
<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　同样的情形也会发生在对数值型字段进行计算的时候：<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
<table style="LINE-HEIGHT: normal; WORD-BREAK: break-all" border=1 borderColor=#cccccc width="90%" bgColor=#e3e3e3 align=center>
    <tbody style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
        <tr style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">SELECT * FROM inventory WHERE Amount/7&lt;24;<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">SELECT * FROM inventory WHERE Amount&lt;24*7;</td>
        </tr>
    </tbody>
</table>
<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　上面的两个查询也是返回相同的结果，但后面的查询将比前面的一个快很多。第三，在搜索字符型字段时，我们有时会使用 LIKE 关键字和通配符，这种做法虽然简单，但却也是以牺牲系统性能为代价的。例如下面的查询将会比较表中的每一条记录。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
<table style="LINE-HEIGHT: normal; WORD-BREAK: break-all" border=1 borderColor=#cccccc width="90%" bgColor=#e3e3e3 align=center>
    <tbody style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
        <tr style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">SELECT * FROM books<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">WHERE name like "MySQL%"</td>
        </tr>
    </tbody>
</table>
<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　但是如果换用下面的查询，返回的结果一样，但速度就要快上很多：..<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
<table style="LINE-HEIGHT: normal; WORD-BREAK: break-all" border=1 borderColor=#cccccc width="90%" bgColor=#e3e3e3 align=center>
    <tbody style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
        <tr style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">SELECT * FROM books<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">WHERE name&gt;="MySQL"and name&lt;"MySQM"</td>
        </tr>
    </tbody>
</table>
<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　最后，应该注意避免在查询中让MySQL进行自动类型转换，因为转换过程也会使索引变得不起作用。<br>选自：<br><a href="http://space.itpub.net/47598/viewspace-329728"><u><font color=#0000ff>http://space.itpub.net/47598/viewspace-329728</font></u></a></span></span>
<img src ="http://www.cppblog.com/beautykingdom/aggbug/101825.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2009-11-24 17:01 <a href="http://www.cppblog.com/beautykingdom/archive/2009/11/24/101825.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MySQL索引分析和优化解决方案</title><link>http://www.cppblog.com/beautykingdom/archive/2009/11/24/101823.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Tue, 24 Nov 2009 09:00:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2009/11/24/101823.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/101823.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2009/11/24/101823.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/101823.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/101823.html</trackback:ping><description><![CDATA[<span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: rgb(0,0,0); WORD-SPACING: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class=Apple-style-span><span style="TEXT-ALIGN: left; LINE-HEIGHT: 21px; FONT-FAMILY: Arial, Helvetica, sans-serif; COLOR: rgb(51,51,51); FONT-SIZE: 12px" class=Apple-style-span><strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">一、什么是索引？</strong><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　索引用来快速地寻找那些具有特定值的记录，所有MySQL索引都以B-树的形式保存。如果没有索引，执行查询时MySQL必须从第一个记录开始扫描整 个表的所有记录，直至找到符合要求的记录。表里面的记录数量越多，这个操作的代价就越高。如果作为搜索条件的列上已经创建了索引，MySQL无需扫描任何 记录即可迅速得到目标记录所在的位置。如果表有1000个记录，通过索引查找记录至少要比顺序扫描记录快100倍。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　假设我们创建了一个名为people的表：<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
<table style="LINE-HEIGHT: normal; WORD-BREAK: break-all" border=1 cellSpacing=0 borderColor=#111111 cellPadding=2 bgColor=#e9e9e9 align=center>
    <tbody style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
        <tr style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">CREATE TABLE people ( peopleid SMALLINT NOT NULL, name CHAR(50) NOT NULL );</td>
        </tr>
    </tbody>
</table>
<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　然后，我们完全随机把1000个不同name值插入到people表。下图显示了people表所在数据文件的一小部分：<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
<center style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><img style="LINE-HEIGHT: normal; MAX-WIDTH: 400px; WORD-BREAK: break-all; CURSOR: pointer" title=点击图片可在新窗口打开 border=0 hspace=3 alt=点击查看原图 vspace=3 src="http://www.phpe.net/uploads/images/article_1043248393.gif" width=232 height=115 twffan="done"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"></center><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　可以看到，在数据文件中name列没有任何明确的次序。如果我们创建了name列的索引，MySQL将在索引中排序name列：<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
<center style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><img style="LINE-HEIGHT: normal; MAX-WIDTH: 400px; WORD-BREAK: break-all; CURSOR: pointer" title=点击图片可在新窗口打开 border=0 hspace=3 alt=点击查看原图 vspace=3 src="http://www.phpe.net/uploads/images/article_1043248412.gif" width=162 height=119 twffan="done"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"></center><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　对于索引中的每一项，MySQL在内部为它保存一个数据文件中实际记录所在位置的&#8220;指针&#8221;。因此，如果我们要查找name等于&#8220;Mike&#8221;记录的 peopleid（<a style="LINE-HEIGHT: normal; COLOR: rgb(51,51,51); WORD-BREAK: break-all; TEXT-DECORATION: underline" onclick="javascript:tagshow(event, 'SQL');" href="javascript:;" target=_self><u style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">SQL</strong></u></a>命令为&#8220;SELECT peopleid FROM people WHERE name=\'Mike\';&#8221;），MySQL能够在name的索引中查找&#8220;Mike&#8221;值，然后直接转到数据文件中相应的行，准确地返回该行的 peopleid（999）。在这个过程中，MySQL只需处理一个行就可以返回结果。如果没有&#8220;name&#8221;列的索引，MySQL要扫描数据文件中的所有 记录，即1000个记录！显然，需要MySQL处理的记录数量越少，则它完成任务的速度就越快。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　二、索引的类型</strong><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　MySQL提供多种索引类型供选择：<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
<ul style="PADDING-BOTTOM: 0px; LINE-HEIGHT: normal; MARGIN: 0px 0px 0px 3em; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; WORD-BREAK: break-all; PADDING-TOP: 0px">
    <li style="LINE-HEIGHT: normal; WORD-BREAK: break-all">普通索引<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">这是最基本的索引类型，而且它没有唯一性之类的限制。普通索引可以通过以下几种方式创建：<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
    <ul style="PADDING-BOTTOM: 0px; LINE-HEIGHT: normal; MARGIN: 0px 0px 0px 3em; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; WORD-BREAK: break-all; PADDING-TOP: 0px">
        <li style="LINE-HEIGHT: normal; WORD-BREAK: break-all" type=circle>创建索引，例如CREATE INDEX &lt;索引的名字&gt; ON tablename (列的列表);</li>
        <li style="LINE-HEIGHT: normal; WORD-BREAK: break-all" type=circle>修改表，例如ALTER TABLE tablename ADD INDEX [索引的名字] (列的列表);</li>
        <li style="LINE-HEIGHT: normal; WORD-BREAK: break-all" type=circle>创建表的时候指定索引，例如CREATE TABLE tablename ( [...], INDEX [索引的名字] (列的列表) );</li>
    </ul>
    <br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"></li>
    <li style="LINE-HEIGHT: normal; WORD-BREAK: break-all">唯一性索引<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">这种索引和前面的&#8220;普通索引&#8221;基本相同，但有一个区别：索引列的所有值都只能出现一次，即必须唯一。唯一性索引可以用以下几种方式创建：<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
    <ul style="PADDING-BOTTOM: 0px; LINE-HEIGHT: normal; MARGIN: 0px 0px 0px 3em; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; WORD-BREAK: break-all; PADDING-TOP: 0px">
        <li style="LINE-HEIGHT: normal; WORD-BREAK: break-all" type=circle>创建索引，例如CREATE UNIQUE INDEX &lt;索引的名字&gt; ON tablename (列的列表);</li>
        <li style="LINE-HEIGHT: normal; WORD-BREAK: break-all" type=circle>修改表，例如ALTER TABLE tablename ADD UNIQUE [索引的名字] (列的列表);</li>
        <li style="LINE-HEIGHT: normal; WORD-BREAK: break-all" type=circle>创建表的时候指定索引，例如CREATE TABLE tablename ( [...], UNIQUE [索引的名字] (列的列表) );</li>
    </ul>
    <br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"></li>
    <li style="LINE-HEIGHT: normal; WORD-BREAK: break-all">主键<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">主键是一种唯一性索引，但它必须指定为&#8220;PRIMARY KEY&#8221;。如果你曾经用过AUTO_INCREMENT类型的列，你可能已经熟悉主键之类的概念了。主键一般在创建表的时候指定，例如&#8220;CREATE TABLE tablename ( [...], PRIMARY KEY (列的列表) ); &#8221;。但是，我们也可以通过修改表的方式加入主键，例如&#8220;ALTER TABLE tablename ADD PRIMARY KEY (列的列表); &#8221;。每个表只能有一个主键。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">&nbsp;<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"></li>
    <li style="LINE-HEIGHT: normal; WORD-BREAK: break-all">全文索引<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">MySQL从3.23.23版开始支持全文索引和全文检索。在MySQL中，全文索引的索引类型为FULLTEXT。全文索引可以在VARCHAR或者 TEXT类型的列上创建。它可以通过CREATE TABLE命令创建，也可以通过ALTER TABLE或CREATE INDEX命令创建。对于大规模的数据集，通过ALTER TABLE（或者CREATE INDEX）命令创建全文索引要比把记录插入带有全文索引的空表更快。本文下面的讨论不再涉及全文索引，要了解更多信息，请参见<u style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><font style="LINE-HEIGHT: normal; WORD-BREAK: break-all" color=#0000ff>MySQL documentation</font></u>。</li>
</ul>
　　<strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">三、单列索引与多列索引</strong><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　索引可以是单列索引，也可以是多列索引。下面我们通过具体的例子来说明这两种索引的区别。假设有这样一个people表：<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
<table style="LINE-HEIGHT: normal; WORD-BREAK: break-all" border=1 cellSpacing=0 borderColor=#111111 cellPadding=2 bgColor=#e9e9e9>
    <tbody style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
    </tbody>
</table>
<table style="LINE-HEIGHT: normal; WORD-BREAK: break-all" border=1 cellSpacing=0 borderColor=#111111 cellPadding=5 bgColor=#e9e9e9 align=center>
    <tbody style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
        <tr style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">ALTER TABLE people ADD INDEX fname_lname_age (firstname,lastname,age);</td>
        </tr>
    </tbody>
</table>
<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　由于索引文件以B-树格式保存，MySQL能够立即转到合适的firstname，然后再转到合适的lastname，最后转到合适的age。在没有扫描数据文件任何一个记录的情况下，MySQL就正确地找出了搜索的目标记录！<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　那么，如果在firstname、lastname、age这三个列上分别创建单列索引，效果是否和创建一个firstname、lastname、 age的多列索引一样呢？答案是否定的，两者完全不同。当我们执行查询的时候，MySQL只能使用一个索引。如果你有三个单列的索引，MySQL会试图选 择一个限制最严格的索引。但是，即使是限制最严格的单列索引，它的限制能力也肯定远远低于firstname、lastname、age这三个列上的多列 索引。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　四、最左前缀</strong><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　多列索引还有另外一个优点，它通过称为最左前缀（Leftmost Prefixing）的概念体现出来。继续考虑前面的例子，现在我们有一个firstname、lastname、age列上的多列索引，我们称这个索引 为fname_lname_age。当搜索条件是以下各种列的组合时，MySQL将使用fname_lname_age索引：<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
<ul style="PADDING-BOTTOM: 0px; LINE-HEIGHT: normal; MARGIN: 0px 0px 0px 3em; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; WORD-BREAK: break-all; PADDING-TOP: 0px">
    <li style="LINE-HEIGHT: normal; WORD-BREAK: break-all">firstname，lastname，age</li>
    <li style="LINE-HEIGHT: normal; WORD-BREAK: break-all">firstname，lastname</li>
    <li style="LINE-HEIGHT: normal; WORD-BREAK: break-all">firstname</li>
</ul>
　　从另一方面理解，它相当于我们创建了(firstname，lastname，age)、(firstname，lastname)以及(firstname)这些列组合上的索引。下面这些查询都能够使用这个fname_lname_age索引：<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">&nbsp;<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><u style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><font style="LINE-HEIGHT: normal; WORD-BREAK: break-all" color=#0000ff></font></u>
<table style="LINE-HEIGHT: normal; WORD-BREAK: break-all" border=1 cellSpacing=0 borderColor=#111111 cellPadding=5 bgColor=#e9e9e9>
    <tbody style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
    </tbody>
</table>
<table style="LINE-HEIGHT: normal; WORD-BREAK: break-all" border=1 cellSpacing=0 borderColor=#111111 cellPadding=5 bgColor=#e9e9e9 align=center>
    <tbody style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
        <tr style="LINE-HEIGHT: normal; WORD-BREAK: break-all" align=middle bgColor=#dbdbdb>
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">table</td>
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">type</td>
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">possible_keys</td>
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">key</td>
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">key_len</td>
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">ref</td>
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">rows</td>
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">Extra</td>
        </tr>
        <tr style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">people</td>
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">ref</td>
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">fname_lname_age</td>
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">fname_lname_age</td>
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">102</td>
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">const,const,const</td>
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">1</td>
            <td style="LINE-HEIGHT: normal; WORD-BREAK: break-all">Where used</td>
        </tr>
    </tbody>
</table>
<font style="LINE-HEIGHT: normal; WORD-BREAK: break-all" color=#0000ff><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　下面我们就来看看这个EXPLAIN分析结果的含义。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">
<ul style="PADDING-BOTTOM: 0px; LINE-HEIGHT: normal; MARGIN: 0px 0px 0px 3em; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; WORD-BREAK: break-all; PADDING-TOP: 0px">
    <li style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">table</strong>：这是表的名字。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"></li>
    <li style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">type</strong>：连接操作的类型。下面是MySQL文档关于ref连接类型的说明：<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">&#8220;对于每一种与另一个表中记录的组合，MySQL将从当前的表读取所有带有匹配索引值的记录。如果连接操作只使用键的最左前缀，或者如果键不是 UNIQUE或PRIMARY KEY类型（换句话说，如果连接操作不能根据键值选择出唯一行），则MySQL使用ref连接类型。如果连接操作所用的键只匹配少量的记录，则ref是一 种好的连接类型。&#8221;<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">在本例中，由于索引不是UNIQUE类型，ref是我们能够得到的最好连接类型。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">如果EXPLAIN显示连接类型是&#8220;ALL&#8221;，而且你并不想从表里面选择出大多数记录，那么MySQL的操作效率将非常低，因为它要扫描整个表。你可以加入更多的索引来解决这个问题。预知更多信息，请参见MySQL的手册说明。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"></li>
    <li style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">possible_keys</strong>：<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">可能可以利用的索引的名字。这里的索引名字是创建索引时指定的索引昵称；如果索引没有昵称，则默认显示的是索引中第一个列的名字（在本例中，它是&#8220;firstname&#8221;）。默认索引名字的含义往往不是很明显。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"></li>
    <li style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">Key</strong>：<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">它显示了MySQL实际使用的索引的名字。如果它为空（或NULL），则MySQL不使用索引。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"></li>
    <li style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">key_len</strong>：<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">索引中被使用部分的长度，以字节计。在本例中，key_len是102，其中firstname占50字节，lastname占50字节，age占2字节。如果MySQL只使用索引中的firstname部分，则key_len将是50。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"></li>
    <li style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">ref</strong>：<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">它显示的是列的名字（或单词&#8220;const&#8221;），MySQL将根据这些列来选择行。在本例中，MySQL根据三个常量选择行。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"></li>
    <li style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">rows</strong>：<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">MySQL所认为的它在找到正确的结果之前必须扫描的记录数。显然，这里最理想的数字就是1。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"></li>
    <li style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">Extra</strong>：<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">这里可能出现许多不同的选项，其中大多数将对查询产生负面影响。在本例中，MySQL只是提醒我们它将用WHERE子句限制搜索结果集。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"></li>
</ul>
　　<strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">七、索引的缺点</strong><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　到目前为止，我们讨论的都是索引的优点。事实上，索引也是有缺点的。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　首先，索引要占用磁盘空间。通常情况下，这个问题不是很突出。但是，如果你创建每一种可能列组合的索引，索引文件体积的增长速度将远远超过数据文件。如果你有一个很大的表，索引文件的大小可能达到操作系统允许的最大文件限制。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　第二，对于需要写入数据的操作，比如DELETE、UPDATE以及INSERT操作，索引会降低它们的速度。这是因为MySQL不仅要把改动数据写入数据文件，而且它还要把这些改动写入索引文件。<br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　<strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">【结束语】</strong><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><br style="LINE-HEIGHT: normal; WORD-BREAK: break-all">　　在大型<a style="LINE-HEIGHT: normal; COLOR: rgb(51,51,51); WORD-BREAK: break-all; TEXT-DECORATION: underline" onclick="javascript:tagshow(event, '%CA%FD%BE%DD%BF%E2');" href="javascript:;" target=_self><u style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><strong style="LINE-HEIGHT: normal; WORD-BREAK: break-all">数据库</strong></u></a>中，索引是提高速度的一个关键因素。不管表的结构是多么简单，一次500000行的表扫描操作无论如何不会快。如果你的网站上也有这种大规模的表，那么你确实应该花些时间去分析可以采用哪些索引，并考虑是否可以改写查询以优化应用。要了解更多信息，请参见<u style="LINE-HEIGHT: normal; WORD-BREAK: break-all"><font style="LINE-HEIGHT: normal; WORD-BREAK: break-all" color=#0000ff>MySQL manual</font></u>。另外注意，本文假定你所使用的MySQL是3.23版，部分查询不能在3.22版MySQL上执行。<br><br>转自：<br><a href="http://space.itpub.net/47598/viewspace-329730"><u><font color=#810081>http://space.itpub.net/47598/viewspace-329730</font></u></a></font></span></span>
<img src ="http://www.cppblog.com/beautykingdom/aggbug/101823.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2009-11-24 17:00 <a href="http://www.cppblog.com/beautykingdom/archive/2009/11/24/101823.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>优化Derby数据库技巧</title><link>http://www.cppblog.com/beautykingdom/archive/2009/11/24/101817.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Tue, 24 Nov 2009 08:40:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2009/11/24/101817.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/101817.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2009/11/24/101817.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/101817.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/101817.html</trackback:ping><description><![CDATA[
<div>Dejan Bosanac是一个软件开发者，技术顾问和作家。他关注不同技术的集成和互操作，尤其是与Java以及Web开发相关的领域。</div><div><br></div><div>数据库在操作少量测试数据和大量数据的时候，表现行为上有很大的差异。通常，在开发过程前期，人们不会关注数据库性能的问题，但是随着时间的发展，人们必须采取一些措施来保证数据库在大量数据的情况下正常工作。</div><div><br></div><div>Derby这个完全Java开发的开源的数据库也不例外，因此你必须保证它不会成为你程序的一个瓶颈。尽管人们可以在Derby的手册中找到关于这 个话题全面的资料，我还是想更详尽的关注一下这些问题，基于我的经验提供一些具体的例子。本文将着重于那些由在大的数据表中选择查询数据而产生的程序性能 问题。</div><div><br></div><div>首先，有很多关于调整Derby属性（诸如页面大小和缓存大小等）的技巧。修改这些参数可以在一定程度上调整数据库的性能，但是在通常情况下，更主要的问题来自与你的程序和数据库的设计，因此，我们必须首先关注这些问题，最后再来考虑Derby的属性。</div><div><br></div><div>在接下来的段落里，我将介绍一些能够优化程序中有问题部分的技术。但是，和其他性能优化操作一样，我们需要在优化前先测量并确认问题所在。</div><div><br></div><div>一个简单的例子</div><div><br></div><div>让我们从一个简单的例子开始：假设我们Web程序中拥有一个&#8220;search/list&#8221;的页面，要处理一个有接近100，000行的表，并且那个表 不是很小的（至少有10栏）。用简单的JDBC来写一个例子，这样我们可以专注在数据库和JDBC问题上来。这篇文章中介绍的所有准则对所有的面向对象的 映射工具都适用。</div><div><br></div><div>为了使得用户能够列出一个大的表，通常使用下面简单的查询语句。 select * from tbl</div><div><br></div><div><br></div><div>对应的JDBC语句如下：Class.forName("org.apache.derby.jdbc.ClientDriver").newInstance();</div><div>Connection connection = DriverManager.getConnection (</div><div>"jdbc:derby://localhost:1527/testDb;");</div><div>Statement stmt = connection.createStatement();</div><div>ResultSet rs = stmt.executeQuery("select * from tbl");</div><div>ArrayList allResults = new ArrayList();</div><div>while (rs.next()) {</div><div>// Object-Relation mapping code to populate your</div><div>// object from result set row</div><div>DomainObject domainObject = populate(rs);</div><div>allResults.add(modelObject);</div><div>}</div><div>System.out.println("Results Size: " + allResults.size());</div><div><br></div><div><br></div><div>在这儿，我们碰到了第一个问题。执行这样的代码，并产生100，000（或更多）个domain对象将肯定会导致java用完堆栈空间，产生一个 &#8220;java.lang.OutOfMemoryError&#8221;的错误。对于初学者来说，我们首先必须找到一个方法来使得这个程序工作。</div><div><br></div><div>分页Result Sets</div><div><br></div><div>随着程序中数据量的增多，你首先想到的应该做的事就是为特定的记录（通常是视图）提供分页支持。正如你在这个介绍性的例子中看到的，简单地去获取庞大的result sets很容易导致 out of memory的错误。</div><div><br></div><div>许多数据库服务器支持特定的SQL结构，它们可以用于获得一个查询结果的特定的子集。例如，在MySQL中，提供了LIMIT和OFFSET关键字，它们可以用于select查询。因此，如果你执行类似下面的查询：select * from tbl LIMIT 50 OFFSET 100&nbsp;</div><div><br></div><div><br></div><div>你的结果集将包含从第100个结果开始的50行，即使原先的查询返回了100，000行。许多其他的数据库提供商通过不同的结构提供了相似的功能。 不幸的是，Derby并没有提供这样的功能，所以你必须继续使用原先的&#8220;select * from tbl&#8221;查询语句，然后在应用程序中实现一个分页的机制。让我们来看下面的例子：Class.forName("org.apache.derby.jdbc.ClientDriver").newInstance();</div><div>Connection connection = DriverManager.getConnection(</div><div>"jdbc:derby://localhost:1527/testDb;");</div><div>Statement stmt = connection.createStatement();</div><div>ResultSet rs = stmt.executeQuery("SELECT * FROM tbl");</div><div>ArrayList allResults = new ArrayList();</div><div>int i = 0;</div><div>while (rs.next()) {</div><div>if (i &gt; 50 &amp;&amp; i &lt;= 100) {</div><div>// O-R mapping code populate your row from result set</div><div>DomainObject domainObject = populate(rs);</div><div>allResults.add(modelObject);</div><div>}</div><div>i++;</div><div>}</div><div>System.out.println("Results Size: " + allResults.size());</div><div><br></div><div><br></div><div>通过这些额外的语句，我们提供了&#8220;分页&#8221;的功能。尽管所有的结果都从数据库服务器中取出了，但是只有那些我们感兴趣的行才真正的映射到了Java的 对象中。现在我们避免了先前碰到的&#8220;OutOfMemoryError&#8221;的问题了，这样保证了我们的程序可以真正的工作在大的数据表上。</div><div><br></div><div>然而，通过这个解决方案，数据库仍然会扫描整个表，然后返回所有的行，这还是一个非常消耗时间的任务。对于我的事例数据库来说，这个操作的执行要花费10秒钟，这在程序中显然是不可接受的。</div><div><br></div><div>因此，我们必须给出一个解决方案；我们并不需要返回所有的数据库行，而只需要那些我们感兴趣的（或者至少是所有行的最小可能子集）。我们这儿使用的 技巧就是显式的告诉JDBC驱动我们需要多少行。我们可以使用java.sql.Statement接口提供的setMaxRows（）函数来完成这个任 务。看下面的例子：Class.forName("org.apache.derby.jdbc.ClientDriver").newInstance();</div><div>Connection connection = DriverManager.getConnection(</div><div>"jdbc:derby://localhost:1527/testDb;");</div><div>Statement stmt = connection.createStatement();</div><div>stmt.setMaxRows(101);</div><div>ResultSet rs = stmt.executeQuery("SELECT * FROM tbl");</div><div>ArrayList allResults = new ArrayList();</div><div>int i = 0;</div><div>while (rs.next()) {</div><div>if (i &gt; 50 &amp;&amp; i &lt;= 100) {</div><div>// O-R mapping code populate your row from result set</div><div>DomainObject domainObject = populate(rs);</div><div>allResults.add(modelObject);</div><div>}</div><div>}</div><div>System.out.println("Results Size: " + allResults.size());</div><div><br></div><div><br></div><div>值得注意的是，我们把最大行的值设置为了我们需要的最后一行（增加了1）。因此，通过这样的解决方案，我们不是仅仅取得了我们想要的50行，而是先 获取了100行，然后从中筛选出我们感兴趣的50行。不幸的是，我们没有办法告诉JDBC驱动从一个具体的行开始，因此我们必须说明要显示的记录的最大行 数。这就意味着返回最初的一些记录的操作的性能是很好的，但是随着用户浏览的结果的增多，性能也会下降。好消息就是在大多数的情形下，用户不会浏览的太多 的记录，他们会在前几条记录重获得他们寻找的行，或者改变查询策略。在我本人的环境中，上述的例子的执行时间从8秒降到了0.8秒。</div><div><br></div><div>这是一个描述如何浏览整个表的简单的例子。但是当查询语句中增加了特定的where条件和排序信息时，事情又开始变化了。在接下来的部分里，我将解释为什么这种情况会发生，以后我们如何保证在那些例子中获得可接受的性能。</div><div><div>确保使用索引（避免全表扫描）</div><div><br></div><div>索引在数据库设计中是一个非常重要的概念。因为本文所涉及的范围有限，我并不会详细的介绍索引理论。简单来说，索引是特定的数据库结构，能够允许对 表中的行进行快速访问。索引通常是在一栏或多栏上创建的，因为他们比整个表小了很多，他们的主要用处就是快速搜索一栏（多栏）中的值。</div><div><br></div><div>Derby自动的为主键和外键的栏以及具有唯一性限制的栏创建索引。对于其他任何栏，我们必须显式的创建索引。在接下来的段落中，我们将研究一些例子来介绍索引在什么时候有用以及为什么有用。</div><div><br></div><div>但是首先，我们必须做一些准备。在我们开始优化之前，我们需要能够了解我们执行查询操作的时候数据库中发生了什么。Derby提供了 derby.language.logQueryPlan这个参数。如果设置了这个参数，Derby将会把所有执行的查询的查询计划（query plan）记录在derby.log这个文件中（这个文件在derby.system.home文件夹中）。我们可以在启动服务器之前通过合适的 derby.properties文件或者执行如下的java语句来设置该参数。 System.setProperty("derby.language.logQueryPlan", "true");</div><div><br></div><div><br></div><div>通过检查查询计划，我们可以观察Derby在查询中是使用了索引还是进行了全表查询，全表查询是一个很耗时间的操作。</div><div><br></div><div>既然我们已经设置好了环境，我们可以开始我们的例子了。假设我们先前使用的表 tb1中有一个没有索引的栏叫做owner。因为对查询结果的排序通常是查询性能低下的主要原因，我将介绍所有与排序有关的优化。现在，如果我们希望修改 先前的例子来根据这一栏的值来排序我们的结果，我们需要把我们的查询语句改成如下的样子： SELECT * FROM tbl ORDER BY owner</div><div><br></div><div><br></div><div>如果我们用这个查询语句代替先前的语句，执行的时间将是先前的好多倍。尽管我们分页（paginated）了所有的结果，并小心的设置了要获取的行数，总的执行时间将会是8秒。</div><div><br></div><div>如果我们查看derby.log文件中查询执行计划，我们可以轻易的发现问题：Table Scan ResultSet for TBL at read committed isolation</div><div>level using instantaneous share row locking chosen</div><div>by the optimizer</div><div><br></div><div><br></div><div>这意味着Derby为了将记录排序，是在整个表中执行了查找这个操作。那我们可以做些什么来改善这个情况呢？答案很简单，在这一栏上创建一个索引。我们可以通过如下的SQL语句来做这件事： CREATE INDEX tbl_owner ON tbl(owner)</div><div><br></div><div><br></div><div>如果我们重复我们先前的例子，我们将得到一个和我们没有做排序前的那个例子相似的结果（在我的机器上是不到1秒）。</div><div><br></div><div>同样，如果你现在查询derby.log，你将看到下面的信息（而不是和上面的一样的）：Index Scan ResultSet for TBL using index TBL_OWNER</div><div>at read committed isolation level using share row locking</div><div>chosen by the optimizer</div><div><br></div><div><br></div><div>这就意味着我们可以确保Derby使用了刚创建的索引来获取合适的行。</div><div><br></div><div>使用合适的索引顺序</div><div><br></div><div>我们已经看到了索引是如何帮助我们改善了排序某一栏数据时的性能。但是如果我们尝试去反转排序的顺序的时候会发生什么呢？假设我们希望根据owner栏降序分类我们的数据。在这种情况下，我们原先的查询就会变成如下的语句： SELECT * FROM tbl ORDER BY owner DESC</div><div><br></div><div><br></div><div>注意，我们增加了DESC这个关键字，该关键字将按降序来排序我们的结果。如果我们执行这个新修改过的查询语句，将会发现整个执行的时间又增加到先前的8－9秒。并且，在日志文件中，你将会发现又是执行了全表扫描。</div><div><br></div><div>解决的方法就是为这一栏创建一个降序的索引。对于我们的owner栏，我们执行如下的SQL语句。 CREATE INDEX tbl_owner_desc ON tbl(owner desc)</div><div><br></div><div><br></div><div>现在我们对这一栏有两个索引了（两个顺序），因此查询性能又恢复到了可接受的范围了。注意查询日志中这一行：Index Scan ResultSet for TBL using index TBL_OWNER_DESC</div><div>at read committed isolation level using share row locking</div><div>chosen by the optimizer</div><div>这使我们确信我们使用了新建的索引。因此，如果你经常要对结果进行降序排序的话，你应该考虑创建一个合适的索引来获取更高的性能。</div><div>转自：</div><div>http://space.itpub.net/?uid-47598-action-viewspace-itemid-207379</div></div><img src ="http://www.cppblog.com/beautykingdom/aggbug/101817.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2009-11-24 16:40 <a href="http://www.cppblog.com/beautykingdom/archive/2009/11/24/101817.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Informix数据库的锁技术 </title><link>http://www.cppblog.com/beautykingdom/archive/2009/11/15/101025.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Sun, 15 Nov 2009 15:22:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2009/11/15/101025.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/101025.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2009/11/15/101025.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/101025.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/101025.html</trackback:ping><description><![CDATA[

<div><div style="MARGIN: 15px" id="art" width="100%">
<div><font color="#000000">INFORMIX使用锁技术解决在多用户访问数据库情况下，对同一对象访问的并发控制问题。INFORMIX支持复杂的、可伸缩性的锁技术。 
<br><br><font color="#0000ff">锁的类型</font> <br><br>INFORMIX有三种不同类型的锁。它们在不同的情况下使用。 
<br><br><font color="#0000ff">1.&nbsp;SHARED锁 <br></font><br>&nbsp;&nbsp;&nbsp; 
SHARED锁只保留对象的可读性。当锁存在时，对象不能改变。多个程序可对同个对象加SHARED锁。 <br><br><font color="#0000ff">2.&nbsp;EXCLUSIVE锁 <br></font><br>&nbsp;&nbsp;&nbsp; 
只能使单个程序使用。在程序要改变对象时使用。当其他锁存在时，EXCLUSIVE锁不能使用。当使用了EXCLUSIVE&nbsp;锁后，其他锁不能用于同一对象。 
<br><br><font color="#0000ff">3.&nbsp;PROMOTABLE锁</font> <br><br>&nbsp;&nbsp;&nbsp; 
实现更新的目的。PROMOTABLE锁可以放在已经有SHARED锁的记录，但不能放在已经有PROMOTABLE锁和EXCLUSIVE锁的地方。当记录上无其他锁（含SHARED&nbsp;锁）情况下，这时在程序准备改变锁的记录时，PROMOTABLE锁可以提升为EXCLUSIVE锁。如果在已有SHARED锁的记录上设置了PROMOTABLE锁，在PROMOTABLE锁可以提升到EXCLUSIVE锁之前需要删除SHARED&nbsp;锁。PROMOTABLE锁只能在INFORMIX&nbsp;Universal&nbsp;Server中支持。 
<br><br><font color="#0000ff">锁的范围</font> <br><br>&nbsp;&nbsp;&nbsp; 
INFORMIX对于数据锁定提供了三种不同的方式，范围由大到小分别是数据库、表、记录级锁。使用的时机要看应 <br>用状况而定。 <br><br><font color="#0000ff">1.&nbsp;数据库级锁 <br></font><br>&nbsp;&nbsp;&nbsp; 
你可以用CONNECT,&nbsp;DATABASE,&nbsp;或&nbsp;CREATE&nbsp;DATABASE语句打开数据库。打开数据库的操作就在数据库上设置了SHARED锁。只要程序打开一个数据库，SHARED锁就会阻止其他程序删除数据库或在数据库上设置EXCLUSIVE锁。你可以用语句DATABASE&nbsp;database&nbsp;name&nbsp;EXCLUSIVE锁定整个数据库。若此时其他用户正在使用该数据库，该操作将返回错误。一旦设置了EXCLUSIVE锁，其他程序就不能打开数据库，因为打开时要放置一个SHARED锁。只有数据库关闭时，数据库锁才释放。你可以用DISCONNECT或CLOSE&nbsp;DATABASE显示地处理，也可以运行其他的DATABASE语句隐含的处理。一般数据库级EXCLUSIVE锁是独占数据库资源，防止其他程序访问数据库。它使得程序非常简单，不会产生并发效果。常用在非高峰时期要改变大量数据时如数据库备份过程。 
<br><br><font color="#0000ff">2.&nbsp;表级锁</font> <br><br>&nbsp;&nbsp;&nbsp; 
INFORMIX提供两种模式表级锁：EXCLUSIVE&nbsp;MODE&nbsp;和SHARE&nbsp;MODE。你可以锁整个表。在某些情况下，这个操作是自动进行。当INFORMIX处理下列语句时，一般锁整个的表：ALTER&nbsp;INDEX&nbsp;、ALTER&nbsp;TABLE&nbsp;、CREATE&nbsp;INDEX、DROP&nbsp;INDEX&nbsp;、RENAME&nbsp;COLUMN、RENAME&nbsp;TABLE&nbsp;。该语句结束或事务结束会释放该锁。在某些查询语句中，INFORMIX也自动锁整个表。你可以用LOCK&nbsp;TABLE语句显示地锁整个表。该语句允许你对整个表设置EXCLUSIVE锁或SHARED锁。当你程序从表中读取数据时，SHARED锁防止表中数据更新。INFORMIX&nbsp;Universal&nbsp;Server&nbsp;通过设置隔离级别实现更大程度并发数据保护。&nbsp;</font></div>
<div><font color="#000000"><br>&nbsp;&nbsp;&nbsp; 
表级EXCLUSIVE锁防止对同个表的并发使用。因此，如果其他许多程序要使用该表时，系统性能会受到严重影响。类似数据库级EXCLUSIVE锁，表级EXCLUSIVE锁常用在非高峰时期要改变大量数据时。例如，有些应用在高峰期间并不更新表，它们可以在非高峰期间定期以批处理方式更新。 
<br><br>&nbsp;&nbsp;&nbsp; 通过UNLOCK&nbsp;TABLE&nbsp;table&nbsp;name&nbsp;解除锁。当存在事务时，事务结束时解除锁。 <br><br><font color="#0000ff">3.&nbsp;记录级、页级、键字级锁</font> <br><br>&nbsp;&nbsp;&nbsp; 
表的一个记录是可设置锁的最小对象。一个程序可以锁一个记录或记录的集合，同时其他程序可以操作同一个表的其他记录。Universal&nbsp;Server&nbsp;以磁盘页面（disk&nbsp;pages）为单位存储数据。一个磁盘页面包含一个或多个记录。在有些情况下，页级锁比单个锁更好些。其他数据库服务器可能不存在页级、键字级锁。 
<br><br>&nbsp;&nbsp;&nbsp; 
在Universal&nbsp;Server上，当你创建表时，你可以选择使用记录级锁或页级锁。其他的数据库服务器不提供这种选择。页级、记录级锁有相同的效果。当Universal&nbsp;Server需要锁一个记录时，根据表创建时的锁模式，锁这个记录或记录所在的页面。在一定情况下，数据库服务器需要锁一个不存在的记录。它的效果相当于在记录将要存在的地方放一个<br>锁。当表使用记录锁时，对假想的记录使用键字锁。当表使用页级锁时，含有或可能含有键字的索引页将被设置键级锁。 
</font></div><font color="#000000">
<div><br><font color="#0000ff">锁的时期</font> <br><br>&nbsp;&nbsp;&nbsp; 
程序控制数据库级锁的时期。数据库关闭时，数据库锁级也就释放。表级、记录级、索引级锁的时期依赖于使用的SQL语句以及是否使用事务。如果数据库没有使用事务，也就是说，事务日志不存在并且你没有使用COMMIT&nbsp;WORK语句，当运行UNLOCK&nbsp;TABLE语句时，表级锁就释放。当使用了事务时，事务结束，表级、记录级、索引级锁都释放。</div>
<div>&nbsp;</div>
</font><div><font color="#000000"><font color="#0000ff">修改时锁的处理</font> <br><br>&nbsp;&nbsp;&nbsp; 
当数据库服务器通过一个更新游标取一条记录时，它在该记录上设置一个PROMOTABLE锁。如果这个动作成功，数据库服务器知道其他程序不能改变此记录。因为PROMOTABLE锁不是独占的，其他程序能够继续读这条记录。由于在取此记录的程序执行UPDATE、DELETE语句或简单地取下一条记录之前，它可能花一些时间。这样就提高了性能。当它改变一个记录时，数据库服务器在这条记录上设置一个EXCLUSIVE锁。如果它已经有一个PROMOTABLE锁，它将锁改为EXCLUSIVE状态。 
<br><br>&nbsp;&nbsp;&nbsp; EXCLUSIVE锁的时期依赖于是否使用事务。如果没有使用事务，被修改的记录写到磁盘上就会释放该锁。当使用了事务时， 
锁就会保持到事务的结束。这个动作防止其他程序使用可能回滚到原来状态的记录。 <br><br>&nbsp;&nbsp;&nbsp; 
当使用了事务时，只要删除记录键级锁就会设置。使用键级锁解决下列错误：程序A删除一个记录，程序B插入有同样键的记录。程序A回滚事务，使数据库服务器恢复了删除的记录，这时程序B插入的记录怎么办？通过锁索引，数据库服务器等到程序A提交事务时才插入记录。 
<br><br>&nbsp;&nbsp;&nbsp; 
由于&nbsp;Universal&nbsp;Server数据库服务器管理自己的锁，所以它能提供不同类型的锁。其他的数据库服务器是通过操作系统的特性实现锁，所以不能提供多种选择。有些操作系统通过操作系统服务方式向外提供锁函数。在这些系统，数据库支持SET&nbsp;LOCK&nbsp;MODE语句。而有些操作系统不支持内核级的特性，数据库这时通过在数据库目录下产生小文件实现锁。这些文件带有.lok后缀。如果你的程序使用单个SELECT语句或没有用FOR&nbsp;UPDATE声明的游标提取一个记录，此记录不管是否被一个未完成的交易上锁会马上被提取。这样能产生最好的性能。当你使用FOR&nbsp;UPDATE声明的游标时，它在提取前将当前记录上锁。如果当前记录已经有锁，随作选择模式的不同，程序会等待或返回错误。当取下一个记录时，数据库看当前记录是否更新（使用带WHERE&nbsp;CURRENT&nbsp;OF&nbsp;的UPDATE) 
<br><br><br><font color="#0000ff">锁的模式 
<br></font><br>锁的模式决定程序遇到被锁的数据会产生怎样的结果。当程序要提取或修改一个上锁的记录时，会有下面几种情况： <br><br><font color="#0000ff">1、&nbsp;数据库马上通过SQLCODE变量或SQLSTATE结构给程序返回一个错误代码。 
<br><br>2、&nbsp;在数据解锁前，数据库将程序挂起。 <br><br>3、数据库将程序挂起一段时间。如果锁还未解，数据库给程序返回一个错误代码。</font> 
<br><br>你可以通过SET&nbsp;LOCK&nbsp;MODE模式选择以上结果。 
<br><br>如果你喜欢程序等待（对大多数程序而言这是最好的选择），运行下列语句：SET&nbsp;LOCK&nbsp;MODE&nbsp;TO&nbsp;WAIT。 <br><br>&nbsp;&nbsp;&nbsp; 
当设置了锁模式后，程序常忽视其他并发程序的存在性。如果程序需要访问其他程序已上锁的记录时，它等待别的程序解锁，然后继续。延迟的时间常不可预测。 
<br><br>&nbsp;&nbsp;&nbsp; 
等待解锁不利的一面就是可能会等待很长时间。如果不能接受很长延迟，程序可以运行下列语句：SET&nbsp;LOCK&nbsp;MODE&nbsp;TONOT&nbsp;WAIT选择不等待。当程序需要一个锁记录时，它马上返回一个错误代码，且当前的SQL语句终止。这时，程序必须回滚当前的交易再试一次。程序开始时，数据库初始设置为不等待。 
<br><br>&nbsp;&nbsp;&nbsp; 当你使用UNIVERSAL&nbsp;SERVER时，你有另外的选择。你可以让数据库设置等待时间的上限。你可用下列语句：SETLOCK&nbsp;MODE 
TO&nbsp;WAIT&nbsp;18让数据库有18秒等待上限。若期间锁还没有解开，将返回错误代码。 <br><br>&nbsp;&nbsp;&nbsp; 
在每个程序都选择了锁等待模式情况下，有可能出现死锁。死锁是程序之间相互阻塞，每个程序在其他程序要访问的对象上设置了锁。UNIVERSAL&nbsp;SERVER在单个网络服务器情况下会马上检测到死锁。如果程序选择了锁等待模式，通过给程序返回错误代码，你就知道你遇到了死锁。而在多个数据库服务器的情况下，UNIVERSAL&nbsp;SERVER不能马上检测到。每个数据库服务器都设置锁等待的上限。如果超时，数据库服务器就认为发生了死锁且返回相关的错误代码。数据库管理员可以设置和修改等待时间的上限。</font></div>
<div></div>
<div></div>
<div>转自：</div><div>http://blog.chinaunix.net/u/14063/showart.php?id=114859</div></div></div><img src ="http://www.cppblog.com/beautykingdom/aggbug/101025.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2009-11-15 23:22 <a href="http://www.cppblog.com/beautykingdom/archive/2009/11/15/101025.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>锁的用处及脏读、不可重复读和幻觉读的概念</title><link>http://www.cppblog.com/beautykingdom/archive/2009/11/13/100899.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Fri, 13 Nov 2009 15:09:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2009/11/13/100899.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/100899.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2009/11/13/100899.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/100899.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/100899.html</trackback:ping><description><![CDATA[<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 锁就是防止其他事务访问指定的资源的手段。锁是实现并发控制的主要方法，是多个用户能够同时操纵同一个数据库中的数据而不发生数据不一致现象的重要保障。一般来说，锁可以防止脏读、不可重复读和幻觉读。
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 脏读就是指当一个事务正在访问数据，并且对数据进行了修改，而这种修改还没有提交到数据库中，这时，另外一个事务也访问这个数据，然后使用了这个数据。因为这个数据是还没有提交的数据，那么另外一个事务读到的这个数据是脏数据，依据脏数据所做的操作可能是不正确的。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不可重复读是指在一个事务内，多次读同一数据。在这个事务还没有结束时，另外一个事务也访问该同一数据。那么，在第一个事务中的两次读数据之间，由于第二个事务的修改，那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的，因此称为是不可重复读。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 幻觉读是指当事务不是独立执行时发生的一种现象，例如第一个事务对一个表中的数据进行了修改，这种修改涉及到表中的全部数据行。同时，第二个事务也修改这个表中的数据，这种修改是向表中插入一行新数据。那么，以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行，就好象发生了幻觉一样。</p>
<p>隔离的概念:</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ANSI&nbsp;SQL中定义的4个隔离级实际上是用对锁的操作来定义的：&nbsp;&nbsp;脏读:&nbsp;读数据时不加锁。&nbsp;&nbsp;提交读:&nbsp;在读数据之前加一个读锁，读完之后释放锁。&nbsp;&nbsp;可重复读:&nbsp;在读数据之前加一个读锁，读完之后不释放锁，直到事务rollback或者commit后才释放锁。&nbsp;&nbsp;串行化读:&nbsp;在读数据之前在读取的条件上加锁（称为条件锁），读完之后不释放锁，直到事务rollback或者commit后才释放锁。</p>
<br>转自：<br><a href="http://blog.chinaunix.net/u/14063/showart.php?id=114849">http://blog.chinaunix.net/u/14063/showart.php?id=114849</a> 
<img src ="http://www.cppblog.com/beautykingdom/aggbug/100899.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2009-11-13 23:09 <a href="http://www.cppblog.com/beautykingdom/archive/2009/11/13/100899.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>