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

<channel>
	<title>ChenTaoqian&#039;s Blog &#187; SQL</title>
	<atom:link href="http://www.chentaoqian.com/archives/tag/sql/feed" rel="self" type="application/rss+xml" />
	<link>http://www.chentaoqian.com</link>
	<description>主机,企业邮箱,域名,空间,服务器,Java,Oracle,PHP,Linux,JS,MySQL,Apache</description>
	<lastBuildDate>Wed, 30 Nov 2011 14:35:01 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>优化Oracle的SQL语句（六）</title>
		<link>http://www.chentaoqian.com/archives/326</link>
		<comments>http://www.chentaoqian.com/archives/326#comments</comments>
		<pubDate>Thu, 18 Jun 2009 09:44:32 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[oracle]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[优化]]></category>
		<category><![CDATA[性能]]></category>
		<category><![CDATA[效率]]></category>
		<category><![CDATA[索引]]></category>

		<guid isPermaLink="false">http://www.chentaoqian.com/?p=326</guid>
		<description><![CDATA[第十五 基于函数的索引要求等式匹配
上面的例子中，我们创建了基于函数的索引，但是如果执行下面的查询：
select * from emp where substr(ename,1,1)=’S’
得到的执行计划将还是（TABLE ACCESS FULL），因为只有当数据列能够等式匹配时，基于函数的索引才能生效，这样对于这种索引的计划和维护的要求都很高。请注意，向表中添加索引是非常危险的操作，因为这将导致许多查询执行计划的变更。然而，如果我们使用基于函数的索引就不会产生这样的问题，因为Oracle只有在查询使用了匹配的内置函数时才会使用这种类型的索引。
第十六 使用分区索引
在用分析命令对分区索引进行分析时，每一个分区的数据值的范围信息会放入Oracle的数据字典中。Oracle可以利用这个信息来提取出那些只与SQL查询相关的数据分区。
例如，假设你已经定义了一个分区索引，并且某个SQL语句需要在一个索引分区中进行一次索引扫描。Oracle会仅仅访问这个索引分区，而且会在这个分区上调用一个此索引范围的快速全扫描。因为不需要访问整个索引，所以提高了查询的速度。
第十七 使用位图索引
位图索引可以从本质上提高使用了小于1000个唯一数据值的数据列的查询速度，因为在位图索引中进行的检索是在RAM中完成的，而且也总是比传统的B树索引的速度要快。对于那些少于1000个唯一数据值的数据列建立位图索引，可以使执行效率更快。
第十八  决定使用全表扫描还是使用索引
和所有的秘笈一样，最后一招都会又回到起点，最后我们来讨论一下是否需要建立索引，也许进行全表扫描更快。在大多数情况下，全表扫描可能会导致更多的物理磁盘输入输出，但是全表扫描有时又可能会因为高度并行化的存在而执行的更快。如果查询的表完全没有顺序，那么一个要返回记录数小于10％的查询可能会读取表中大部分的数据块，这样使用索引会使查询效率提高很多。但是如果表非常有顺序，那么如果查询的记录数大于40％时，可能使用全表扫描更快。因此，有一个索引范围扫描的总体原则是：
1）对于原始排序的表  仅读取少于表记录数40％的查询应该使用索引范围扫描。反之，读取记录数目多于表记录数的40％的查询应该使用全表扫描。
2）对于未排序的表    仅读取少于表记录数7％的查询应该使用索引范围扫描。反之，读取记录数目多于表记录数的7％的查询应该使用全表扫描。
以上的招式，是完全可以相互结合同时运用的。而且各种方法之间相互影响，紧密联系。这种联系既存在一致性，也可能带来冲突，当冲突发生时，需要根据实际情况进行选择，没有固定的模式。最后决定SQL优化功力的因素就是对ORACLE内功的掌握程度了。
另外，值得注意的是：随着时间的推移和数据的累计与变化，ORACLE对SQL语句的执行计划也会改变，比如：基于代价的优化方法，随着数据量的增大，优化器可能错误的不选择索引而采用全表扫描。这种情况可能是因为统计信息已经过时，在数据量变化很大后没有及时分析表；但如果对表进行分析之后，仍然没有用上合理的索引，那么就有必要对SQL语句用HINT提示，强制用合理的索引。但这种HINT提示也不能滥用，因为这种方法过于复杂，缺乏通用性和应变能力，同时也增加了维护上的代价；相对来说，基于函数右移、去掉“IN ，OR ，&#60;&#62; ，IS NOT NULL ”、分解复杂的SQL语句等等方法，却是“放之四海皆准”的，可以放心大胆的使用。
同时，优化也不是“一劳永逸”的，必须随着情况的改变进行相应的调整。当数据库设计发生变化，包括更改表结构：字段和索引的增加、删除或改名等；业务逻辑发生变化：如查询方式、取值范围发生改变等等。在这种情况下，也必须对原有的优化进行调整，以适应效率上的需求。
]]></description>
		<wfw:commentRss>http://www.chentaoqian.com/archives/326/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>优化Oracle的SQL语句（五）</title>
		<link>http://www.chentaoqian.com/archives/319</link>
		<comments>http://www.chentaoqian.com/archives/319#comments</comments>
		<pubDate>Thu, 18 Jun 2009 09:23:22 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[oracle]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[优化]]></category>
		<category><![CDATA[性能]]></category>
		<category><![CDATA[效率]]></category>
		<category><![CDATA[索引]]></category>

		<guid isPermaLink="false">http://www.chentaoqian.com/?p=319</guid>
		<description><![CDATA[第十一 like子句尽量前端匹配
因为like参数使用的非常频繁，因此如果能够对like子句使用索引，将很高的提高查询的效率。
例6：select * from city where name like ‘%S%’
以上查询的执行计划用了全表扫描（TABLE ACCESS FULL），如果能够修改为：
select * from city where name like ‘S%’。
那么查询的执行计划将会变成（INDEX RANGE SCAN），成功的利用了name字段的索引。这意味着Oracle SQL优化器会识别出用于索引的like子句，只要该查询的匹配端是具体值。因此我们在做like查询时，应该尽量使查询的匹配端是具体值，即使用like ‘S%’。
第十二 用Case语句合并多重扫描
我们常常必须基于多组数据表计算不同的聚集。例如下例通过三个独立查询：
例8：1）select count(*) from emp where sal&#60;1000;
     2）select count(*) from emp where sal between 1000 and 5000;
     3）select count(*) from emp where sal&#62;5000;
这样我们需要进行三次全表查询，但是如果我们使用case语句：
select
count (sale when sal &#60;1000 then 1 else null end) count_poor,
count (sale [...]]]></description>
		<wfw:commentRss>http://www.chentaoqian.com/archives/319/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>优化Oracle的SQL语句（四）</title>
		<link>http://www.chentaoqian.com/archives/315</link>
		<comments>http://www.chentaoqian.com/archives/315#comments</comments>
		<pubDate>Thu, 18 Jun 2009 08:32:04 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[oracle]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[优化]]></category>
		<category><![CDATA[性能]]></category>
		<category><![CDATA[效率]]></category>
		<category><![CDATA[索引]]></category>

		<guid isPermaLink="false">http://www.chentaoqian.com/?p=315</guid>
		<description><![CDATA[第七 索引提高数据分布不均匀时查询效率
索引的选择性低，但数据的值分布差异很大时，仍然可以利用索引提高效率。A、数据分布不均匀的特殊情况下，选择性不高的索引也要创建。
表ServiceInfo中数据量很大，假设有一百万行，其中有一个字段DisposalCourseFlag，取值范围为枚举值：[0，1，2，3，4，5，6，7]。按照前面说的索引建立的规则，“选择性不高的字段不应该建立索引，该字段只有8种取值，索引值的重复率很高，索引选择性明显很低，因此不建索引。然而，由于该字段上数据值的分布情况非常特殊，具体如下表：



取值范围
1~5
6
7


占总数据量的百分比
1%
98%
1%



而且，常用的查询中，查询DisposalCourseFlag&#60;6 的情况既多又频繁，毫无疑问，如果能够建立索引，并且被应用，那么将大大提高这种情况的查询效率。因此，我们需要在该字段上建立索引。
第八 利用HINT强制指定索引
在ORACLE优化器无法用上合理索引的情况下，利用HINT强制指定索引。
继续上面7的例子，ORACLE缺省认定，表中列的值是在所有数据行中均匀分布的，也就是说，在一百万数据量下，每种DisposalCourseFlag值各有12.5万数据行与之对应。假设SQL搜索条件DisposalCourseFlag=2，利用DisposalCourseFlag列上的索引进行数据搜索效率，往往不比全表扫描的高，ORACLE因此对索引“视而不见”，从而在查询路径的选择中，用其他字段上的索引甚至全表扫描。根据我们上面的分析，数据值的分布很特殊，严重的不均匀。为了利用索引提高效率，此时，一方面可以单独对该字段或该表用analyze语句进行分析，对该列搜集足够的统计数据，使ORACLE在查询选择性较高的值时能用上索引；另一方面，可以利用HINT提示，在SELECT关键字后面，加上“/*+ INDEX(表名称，索引名称）*/”的方式，强制ORACLE优化器用上该索引。
比如： select * from  serviceinfo where DisposalCourseFlag=1 ;
上面的语句，实际执行中ORACLE用了全表扫描，加上蓝色提示部分后，用到索引查询。如下：
select /*+  INDEX(SERVICEINFO,IX_S_DISPOSALCOURSEFLAG)  */  *
from  serviceinfo where DisposalCourseFlag=1;
请注意，这种方法会加大代码维护的难度，而且该字段上索引的名称被改变之后，必须要同步所有指定索引的HINT代码，否则HINT提示将被ORACLE忽略掉。
第九 屏蔽无用索引
继续上面8的例子，由于实际查询中，还有涉及到DisposalCourseFlag=6的查询，而此时如果用上该字段上的索引，将是非常不明智的，效率也极低。因此这种情况下，我们需要用特殊的方法屏蔽该索引，以便ORACLE选择其他字段上的索引。比如，如果字段为数值型的就在表达式的字段名后，添加“+ 0”，为字符型的就并上空串：“&#124;&#124;&#8221;"”
如： select * from  serviceinfo where DisposalCourseFlag+ 0 = 6 and workNo =  &#8216;36&#8242; 。
不过，不要把该用的索引屏蔽掉了，否则同样会产生低效率的全表扫描。
第十 分解复杂查询，用常量代替变量
对于复杂的Where条件组合，Where中含有多个带索引的字段，考虑用IF语句分情况进行讨论；同时，去掉不必要的外来参数条件，减低复杂度，以便在不同情况下用不同字段上的索引。
继续上面9的例子，对于包含
Where (DisposalCourseFlag &#60; v_DisPosalCourseFlag) or (v_DisPosalCourseFlag is null) and &#8230;.的查询，(这里v_DisPosalCourseFlag为一个输入变量，取值范围可能为[NULL，0，1，2，3，4，5，6，7])，可以考虑分情况用IF语句进行讨论，类似：
IF v_DisPosalCourseFlag =1 THEN
Where DisposalCourseFlag = 1 and &#8230;.
ELSIF v_DisPosalCourseFlag =2 [...]]]></description>
		<wfw:commentRss>http://www.chentaoqian.com/archives/315/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>优化Oracle的SQL语句（三）</title>
		<link>http://www.chentaoqian.com/archives/311</link>
		<comments>http://www.chentaoqian.com/archives/311#comments</comments>
		<pubDate>Thu, 18 Jun 2009 08:04:25 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[oracle]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[优化]]></category>
		<category><![CDATA[性能]]></category>
		<category><![CDATA[效率]]></category>

		<guid isPermaLink="false">http://www.chentaoqian.com/?p=311</guid>
		<description><![CDATA[第四 尽量去掉&#8221;IN&#8221;、&#8221;OR&#8221;
含有&#8221;IN&#8221;、&#8221;OR&#8221;的Where子句常会使用工作表，使索引失效；如果不产生大量重复值，可以考虑把子句拆开；拆开的子句中应该包含索引。  
例4： select count(*) from stuff where id_no in(&#8216;0&#8242;,&#8217;1&#8242;)（23秒）
可以考虑将in子句分开：   
select count(*) from stuff where id_no=&#8217;0&#8242; 
select count(*) from stuff where id_no=&#8217;1&#8242;
然后再做一个简单的加法，与原来的SQL语句相比，查询速度更快。
第五 尽量去掉 &#8220;&#60;&#62;&#8221;
尽量去掉 &#8220;&#60;&#62;&#8221;，避免全表扫描，如果数据是枚举值，且取值范围固定，则修改为&#8221;OR&#8221;方式。
例5：
 UPDATE SERVICEINFO SET STATE=0 WHERE STATE&#60;&#62;0;
以上语句由于其中包含了&#8221;&#60;&#62;&#8221;，执行计划中用了全表扫描（TABLE ACCESS FULL），没有用到state字段上的索引。实际应用中，由于业务逻辑的限制，字段state为枚举值，只能等于0，1或2，而且，值等于1，2的很少，因此可以去掉&#8221;&#60;&#62;&#8221;，利用索引来提高效率。
修改为：UPDATE SERVICEINFO SET STATE=0  WHERE STATE = 1 OR STATE = 2 。进一步的修改可以参考第4种方法。
第六 去掉Where子句中的IS NULL和IS NOT NULL
Where字句中的IS NULL和IS NOT NULL将不会使用索引而是进行全表搜索，因此需要通过改变查询方式，分情况讨论等方法，去掉Where子句中的IS NULL和IS NOT NULL。
]]></description>
		<wfw:commentRss>http://www.chentaoqian.com/archives/311/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>优化Oracle的SQL语句（二）</title>
		<link>http://www.chentaoqian.com/archives/309</link>
		<comments>http://www.chentaoqian.com/archives/309#comments</comments>
		<pubDate>Thu, 18 Jun 2009 07:52:03 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[oracle]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[优化]]></category>
		<category><![CDATA[性能]]></category>
		<category><![CDATA[效率]]></category>
		<category><![CDATA[索引]]></category>

		<guid isPermaLink="false">http://www.chentaoqian.com/?p=309</guid>
		<description><![CDATA[第一 避免对列的操作
任何对列的操作都可能导致全表扫描，这里所谓的操作包括数据库函数、计算表达式等等，查询时要尽可能将操作移至等式的右边，甚至去掉函数。  
例1：下列SQL条件语句中的列都建有恰当的索引，但30万行数据情况下执行速度却非常慢：   
select * from record where  substrb(CardNo,1,4)=&#8217;5378&#8242;(13秒) 
select * from record where  amount/30&#60; 1000（11秒） 
select * from record where  to_char(ActionTime,&#8217;yyyymmdd&#8217;)=&#8217;19991201&#8242;（10秒） 
由于where子句中对列的任何操作结果都是在SQL运行时逐行计算得到的，因此它不得不进行表扫描，而没有使用该列上面的索引；如果这些结果在查询编译时就能得到，那么就可以被SQL优化器优化，使用索引，避免表扫描，因此将SQL重写如下：
select * from record where CardNo like  &#8216;5378%&#8217;（&#60; 1秒）
select * from record where amount  &#60; 1000*30（&#60; 1秒）
select * from record where ActionTime= to_date (&#8216;19991201&#8242; ,&#8217;yyyymmdd&#8217;)（&#60; 1秒）
差别是很明显的！
第二 避免不必要的类型转换
需要注意的是，尽量避免潜在的数据类型转换。如将字符型数据与数值型数据比较，ORACLE会自动将字符型用to_number()函数进行转换，从而导致全表扫描。
例2：表tab1中的列col1是字符型（char)，则以下语句存在类型转换：
select col1,col2 from tab1 where col1&#62;10，
应该写为： select col1,col2 from tab1 where [...]]]></description>
		<wfw:commentRss>http://www.chentaoqian.com/archives/309/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>优化Oracle的SQL语句（一）</title>
		<link>http://www.chentaoqian.com/archives/306</link>
		<comments>http://www.chentaoqian.com/archives/306#comments</comments>
		<pubDate>Thu, 18 Jun 2009 07:37:15 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[oracle]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[优化]]></category>
		<category><![CDATA[性能]]></category>
		<category><![CDATA[效率]]></category>
		<category><![CDATA[索引]]></category>

		<guid isPermaLink="false">http://www.chentaoqian.com/?p=306</guid>
		<description><![CDATA[一个系统执行效率的高低包括很多因素，而一旦涉及到数据库，那么SQL语句的执行效率就是重中之重，在规模比较大的局点，往往因为一个小的SQL语句不够优化，导致数据库性能急剧下降，小型机idle所剩无几，应用服务器断连、超时，严重影响业务的正常运行。因此，称低效的SQL语句为客服业务的‘恶龙’并不过分。数据库的优化方法有很多种，在应用层来说，主要是基于索引的优化。
建立必要的索引，这一点看似容易实际却很难。难就难在如何判断哪些索引是必要的，哪些又是不必要的。判断的最终标准是看这些索引是否对我们的数据库性能有所帮助。具体到方法上，就必须熟悉数据库应用程序中的所有SQL语句，从中统计出常用的可能对性能有影响的部分SQL，分析、归纳出作为Where条件子句的字段及其组合方式；在这一基础上可以初步判断出哪些表的哪些字段应该建立索引。其次，必须熟悉应用程序。必须了解哪些表是数据操作频繁的表；哪些表经常与其他表进行连接；哪些表中的数据量可能很大；对于数据量大的表，其中各个字段的数据分布情况如何；等等。对于满足以上条件的这些表，必须重点关注，因为在这些表上的索引，将对SQL语句的性能产生举足轻重的影响。
 建立索引常用的规则如下：
1、表的主键、外键必须有索引；
2、数据量超过300的表应该有索引；
3、经常与其他表进行连接的表，在连接字段上应该建立索引；
4、经常出现在Where子句中的字段，特别是大表的字段，应该建立索引；
5、索引应该建在选择性高的字段上；
6、索引应该建在小字段上，对于大的文本字段甚至超长字段，不要建索引；
7、复合索引的建立需要进行仔细分析；尽量考虑用单字段索引代替：
   A、正确选择复合索引中的主列字段，一般是选择性较好的字段；
   B、复合索引的几个字段是否经常同时以AND方式出现在Where子句中？单字段查询是否极少甚至没有？如果是，则可以建立复合索引；否则考虑单字段索引；
   C、如果复合索引中包含的字段经常单独出现在Where子句中，则分解为多个单字段索引；
   D、如果复合索引所包含的字段超过3个，那么仔细考虑其必要性，考虑减少复合的字段；
   E、如果既有单字段索引，又有这几个字段上的复合索引，一般可以删除复合索引；
8、频繁进行数据操作的表，不要建立太多的索引；
9、删除无用的索引，避免对执行计划造成负面影响；
以上是一些普遍的建立索引时的判断依据。一言以蔽之，索引的建立必须慎重，对每个索引的必要性都应该经过仔细分析，要有建立的依据。因为太多的索引与不充分、不正确的索引对性能都毫无益处：在表上建立的每个索引都会增加存储开销，索引对于插入、删除、更新操作也会增加处理上的开销。 另外，过多的复合索引，在有单字段索引的情况下，一般都是没有存在价值的；相反，还会降低数据增加删除时的性能，特别是对频繁更新的表来说，负面影响更大。
]]></description>
		<wfw:commentRss>http://www.chentaoqian.com/archives/306/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>浅谈数据库索引</title>
		<link>http://www.chentaoqian.com/archives/80</link>
		<comments>http://www.chentaoqian.com/archives/80#comments</comments>
		<pubDate>Fri, 05 Jun 2009 10:46:25 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[索引]]></category>

		<guid isPermaLink="false">http://www.chentaoqian.com/?p=80</guid>
		<description><![CDATA[数据库索引是为了增加查询速度而对表字段附加的一种标识。见过很多人机械的理解索引的概念，认为增加索引只有好处没有坏处。这里想把之前的索引学习笔记总结一下：
首先明白为什么索引会增加速度，DB在执行一条Sql语句的时候，默认的方式是根据搜索条件进行全表扫描，遇到匹配条件的就加入搜索结果集合。如果我们对某一字段增加索引，查询时就会先去索引列表中一次定位到特定值的行数，大大减少遍历匹配的行数，所以能明显增加查询的速度。那么在任何时候都应该加索引么？这里有几个反例：1、如果每次都需要取到所有表记录，无论如何都必须进行全表扫描了，那么是否加索引也没有意义了。2、对非唯一的字段，例如&#8221;性别&#8221;这种大量重复值的字段，增加索引也没有什么意义。3、对于记录比较少的表，增加索引不会带来速度的优化反而浪费了存储空间，因为索引是需要存储空间的，而且有个致命缺点是对于update/insert/delete的每次执行，字段的索引都必须重新计算更新。
那么在什么时候适合加上索引呢？我们看一个Mysql手册中举的例子，这里有一条sql语句：
SELECT c.companyID, c.companyName FROM Companies c, User u WHERE c.companyID = u.fk_companyID AND c.numEmployees &#62;= 0 AND c.companyName LIKE &#8216;%i%&#8217; AND u.groupID IN (SELECT g.groupID FROM Groups g WHERE g.groupLabel = &#8216;Executive&#8217;)
这条语句涉及3个表的联接，并且包括了许多搜索条件比如大小比较，Like匹配等。在没有索引的情况下Mysql需要执行的扫描行数是77721876行。而我们通过在companyID和groupLabel两个字段上加上索引之后，扫描的行数只需要134行。在Mysql中可以通过Explain Select来查看扫描次数。可以看出来在这种联表和复杂搜索条件的情况下，索引带来的性能提升远比它所占据的磁盘空间要重要得多。
那么索引是如何实现的呢？大多数DB厂商实现索引都是基于一种数据结构&#8211;B树。因为B树的特点就是适合在磁盘等直接存储设备上组织动态查找表。B树的定义是这样的：一棵m(m&#62;=3)阶的B树是满足下列条件的m叉树：
1、每个结点包括如下作用域(j, p0, k1, p1, k2, p2, &#8230; ki, pi) 其中j是关键字个数，p是孩子指针
2、所有叶子结点在同一层上，层数等于树高h
3、每个非根结点包含的关键字个数满足[m/2-1]&#60;=j&#60;=m-1
4、若树非空，则根至少有1个关键字，若根非叶子，则至少有2棵子树，至多有m棵子树
看一个B树的例子，针对26个英文字母的B树可以这样构造：
 
 
可以看到在这棵B树搜索英文字母复杂度只为o(m)，在数据量比较大的情况下，这样的结构可以大大增加查询速度。然而有另外一种数据结构查询的虚度比B树更快&#8211;散列表。Hash表的定义是这样的：设所有可能出现的关键字集合为u，实际发生存储的关键字记为k，而&#124;k&#124;比&#124;u&#124;小很多。散列方法是通过散列函数h将u映射到表T[0,m-1]的下标上，这样u中的关键字为变量，以h为函数运算结果即为相应结点的存储地址。从而达到可以在o(1)的时间内完成查找。
然而散列表有一个缺陷，那就是散列冲突，即两个关键字通过散列函数计算出了相同的结果。设m和n分别表示散列表的长度和填满的结点数，n/m为散列表的填装因子，因子越大，表示散列冲突的机会越大。
因为有这样的缺陷，所以数据库不会使用散列表来做为索引的默认实现，Mysql宣称会根据执行查询格式尝试将基于磁盘的B树索引转变为和合适的散列索引以追求进一步提高搜索速度。我想其它数据库厂商也会有类似的策略，毕竟在数据库战场上，搜索速度和管理安全一样是非常重要的竞争点。
]]></description>
		<wfw:commentRss>http://www.chentaoqian.com/archives/80/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

