<?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/"
	>

<channel>
	<title>Alibaba DBA Team</title>
	<atom:link href="http://www.alidba.net/index.php/feed" rel="self" type="application/rss+xml" />
	<link>http://www.alidba.net</link>
	<description>这里记录着阿里巴巴数据库团队成员的点点滴滴</description>
	<pubDate>Tue, 24 Aug 2010 09:44:05 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>话说 Oracle ACE 这回事儿</title>
		<link>http://www.alidba.net/index.php/archives/434</link>
		<comments>http://www.alidba.net/index.php/archives/434#comments</comments>
		<pubDate>Tue, 24 Aug 2010 09:44:05 +0000</pubDate>
		<dc:creator>sky</dc:creator>
		
		<category><![CDATA[团队风采]]></category>

		<category><![CDATA[Oracle]]></category>

		<category><![CDATA[oracle ace]]></category>

		<guid isPermaLink="false">http://www.alidba.net/?p=434</guid>
		<description><![CDATA[前段时间，在有幸被多人举荐并由 Oracle 公司的 Jack 提名后，被 Oracle 公司授予了 Oracle ACE (Expertise: MySQL) 称号。
很多朋友听闻此事后都向我道贺，也有很多朋友提出疑问： Oracle ACE 到底为何物？
Oracle ACE 程序主要是 Oracle 公司为了奖励使用推广Oracle公司某个领域产品的技术专家们所做的贡献而设立的一种荣誉机制。目前，除了通过业内知名人士举荐并由 Oracle 公司的人提名最终经过 ACE 程序审核小组评审之外，无法通过认证考试或者是其他途径获得。
目前国内共有 16 位技术专家获此荣誉，分别分布在6个技术领域，如下：

Database Management &#38; Performance：5人
Database App Development：5人
Middleware &#38; SOA：4人
Applications &#38; Apps Technology：1人
MySQL：1人

其中 MySQL  领域目前国内就我一个人（希望在未来能够有越来越多的战友们能够加入这个行列），全球也只有4位。能够获此殊荣，确实非常开心，这是对我个人在这个技术领 域内的认可。当然，这也离不开我所在的公司为我提供的成长平台，离不开所在Team的各位同事给我的帮助。同时，也希望国内有更多的技术专家能够获得  ACE 称号。
原文出自： Sky.Jian  –  i Sky000 
话说 Oracle ACE 这回事儿
]]></description>
			<content:encoded><![CDATA[<p>前段时间，在有幸被多人举荐并由 Oracle 公司的 Jack 提名后，被 Oracle 公司授予了 <a href="http://apex.oracle.com/pls/otn/f?p=19297:4:4314626439976920::NO:4:P4_ID:2560" target="_blank">Oracle ACE (Expertise: MySQL)</a> 称号。</p>
<p>很多朋友听闻此事后都向我道贺，也有很多朋友提出疑问： Oracle ACE 到底为何物？</p>
<p><a href="http://www.oracle.com/technetwork/community/oracle-ace/index.html" target="_blank">Oracle ACE 程序</a>主要是 Oracle 公司为了奖励使用推广Oracle公司某个领域产品的技术专家们所做的贡献而设立的一种荣誉机制。目前，除了通过业内知名人士举荐并由 Oracle 公司的人提名最终经过 ACE 程序审核小组评审之外，无法通过认证考试或者是其他途径获得。</p>
<p>目前国内共有 16 位技术专家获此荣誉，分别分布在6个技术领域，如下：</p>
<ul>
<li>Database Management &amp; Performance：<span style="color: #ff0000;">5人</span></li>
<li>Database App Development：<span style="color: #ff0000;">5人</span></li>
<li>Middleware &amp; SOA：<span style="color: #ff0000;">4人</span></li>
<li>Applications &amp; Apps Technology：<span style="color: #ff0000;">1人</span></li>
<li><strong>MySQL：<span style="color: #ff0000;">1人</span></strong></li>
</ul>
<p>其中 MySQL  领域目前国内就我一个人（希望在未来能够有越来越多的战友们能够加入这个行列），全球也只有4位。能够获此殊荣，确实非常开心，这是对我个人在这个技术领 域内的认可。当然，这也离不开我所在的公司为我提供的成长平台，离不开所在Team的各位同事给我的帮助。同时，也希望国内有更多的技术专家能够获得  ACE 称号。</p>
<p>原文出自： <strong><a href="http://isky000.com/">Sky.Jian  –  i Sky000 </a></strong></p>
<h2><a title="Permanent Link to 话说 Oracle ACE 这回事儿" rel="bookmark" href="http://isky000.com/life-tips/oracle-ace-expertise-mysql">话说 Oracle ACE 这回事儿</a></h2>
]]></content:encoded>
			<wfw:commentRss>http://www.alidba.net/index.php/archives/434/feed</wfw:commentRss>
		</item>
		<item>
		<title>核心业务系统数据库平台迁移： Oracle -&#62; MySQL</title>
		<link>http://www.alidba.net/index.php/archives/432</link>
		<comments>http://www.alidba.net/index.php/archives/432#comments</comments>
		<pubDate>Tue, 24 Aug 2010 09:42:15 +0000</pubDate>
		<dc:creator>sky</dc:creator>
		
		<category><![CDATA[大话技术]]></category>

		<category><![CDATA[MySQL]]></category>

		<category><![CDATA[Oracle]]></category>

		<category><![CDATA[可扩展]]></category>

		<category><![CDATA[数据库迁移]]></category>

		<guid isPermaLink="false">http://www.alidba.net/?p=432</guid>
		<description><![CDATA[为了对核心技术拥有更多的自主控制能力，为了解决数据库的线性扩展问题，为了尽量减少对商业软件的依赖，为了摆脱对高端硬件的依赖，为了…  基于以上多种原因，2年前，我们计划将公司某核心应用平台进行大手术：数据库平台从软件到硬件全部重构。当然，这其中应用架构的改造也不可避免的进行了大 换血。
这个项目无论是从技术角度还是是业务角度来说，都对我们有着非常大的价值，也必定会带来非常深远的影响。项目历时2年多，分4个阶段才完成：

应用接口统一
这一阶段主要是为了后面真正迁移的时候做准备工作，将该核心应用系统的所有数据访问入口统一到一起，全部以服务化的接口方式呈现给其他有需要的系统，一来方便后续变更的控制，二来也推进了服务化的进程。

Oracle数据库中拆分（1拆16）
这个阶段本不是必要的，但是由于项目启动稍微晚了点，数据出现了爆发性增长，导致该系统的数据表太大（单表不带索引过500GB），原  Oracle 数据库已经快撑不住了。为了安全起见，先在 Oracle 中从一个主表以会员ID进行 hash  运算后再进行水平拆分，从1个表分拆成了16个。附表由于访问量稍小，而且全部是根据主键访问，暂时保留原样。
当然，这样的水平拆分，必然会带来数据访问路由以及数据合并的问题。我们专门为此开发了具有分布式数据库路由/数据合并，数据库读写分离，数据库链接管理等功能的数据访问中间层，专门解决拆分后给应用服务器带来的影响，使得应用服务器完全感受不到后端数据库的变化。
这个数据访问中间层，对前端应用服务器来说，就是一个完整的数据库，所有数据请求都从这里实现，以协议的方式和前端应用服务器的jdbc驱动进行交互，以便让数据库对应用服务器彻底透明。

Oracle迁移至 MySQL（16拆128）
这个阶段是整个阶段中历时最长，复杂度最高，风险系数最高的，未知因素也最多的一个阶段。虽然 MySQL 数据库已经在互联网行业占据了大片江山，但是对于阿里巴巴来说，却仍然是一个新鲜玩意儿，因为之前我们一直都用 Oracle 来提供所有的业务系统的数据库服务。
在此之前，我们从来没有在如此核心业务系统的数据库上使用过 PC Server 和本地硬盘来承载数据库，一直是使用 IBM  小型机和中高端存储设备来解决高性能和高可靠的问题。在更换成 PC Server 和本地硬盘来承载数据库之后，我们就必须面对 PC Server  本身硬件可能存在的不可靠性所带来的 Crash，所以我们必须有一套完善的 HA 切换机制，要比小型机厂商所提供的商业 HA  管理软件更加高效更加自动化更加可控，才能我们降低了设备本身可靠性之后达到原有的可用性要求。
对于一个需要满足 365 *  24 * 7 的核心业务系统来说，肯定是不可能给我们太多时间来进行数据迁移的，所以我们不得不设计出一个对现有系统影响尽可能小的迁移方案，这势必会造成方案的高度复杂化，带来更多的风险。最后的迁移方案要经历如下4个阶段：
1. Oracle 读/写;；MySQL 初始化并增量写
2. Oracle 读/写； MySQL 写
3. Oracle 写； MySQL 读/写
4. Oracle [...]]]></description>
			<content:encoded><![CDATA[<p>为了对核心技术拥有更多的自主控制能力，为了解决数据库的线性扩展问题，为了尽量减少对商业软件的依赖，为了摆脱对高端硬件的依赖，为了…  基于以上多种原因，2年前，我们计划将公司某核心应用平台进行大手术：数据库平台从软件到硬件全部重构。当然，这其中应用架构的改造也不可避免的进行了大 换血。</p>
<p>这个项目无论是从技术角度还是是业务角度来说，都对我们有着非常大的价值，也必定会带来非常深远的影响。项目历时2年多，分4个阶段才完成：</p>
<ul>
<li>应用接口统一</li>
<p>这一阶段主要是为了后面真正迁移的时候做准备工作，将该核心应用系统的所有数据访问入口统一到一起，全部以服务化的接口方式呈现给其他有需要的系统，一来方便后续变更的控制，二来也推进了服务化的进程。</ul>
<ul>
<li>Oracle数据库中拆分（1拆16）</li>
<p>这个阶段本不是必要的，但是由于项目启动稍微晚了点，数据出现了爆发性增长，导致该系统的数据表太大（单表不带索引过500GB），原  Oracle 数据库已经快撑不住了。为了安全起见，先在 Oracle 中从一个主表以会员ID进行 hash  运算后再进行水平拆分，从1个表分拆成了16个。附表由于访问量稍小，而且全部是根据主键访问，暂时保留原样。</p>
<p>当然，这样的水平拆分，必然会带来数据访问路由以及数据合并的问题。我们专门为此开发了具有分布式数据库路由/数据合并，数据库读写分离，数据库链接管理等功能的数据访问中间层，专门解决拆分后给应用服务器带来的影响，使得应用服务器完全感受不到后端数据库的变化。</p>
<p>这个数据访问中间层，对前端应用服务器来说，就是一个完整的数据库，所有数据请求都从这里实现，以协议的方式和前端应用服务器的jdbc驱动进行交互，以便让数据库对应用服务器彻底透明。</ul>
<ul>
<li>Oracle迁移至 MySQL（16拆128）</li>
<p>这个阶段是整个阶段中历时最长，复杂度最高，风险系数最高的，未知因素也最多的一个阶段。虽然 MySQL 数据库已经在互联网行业占据了大片江山，但是对于阿里巴巴来说，却仍然是一个新鲜玩意儿，因为之前我们一直都用 Oracle 来提供所有的业务系统的数据库服务。</p>
<p>在此之前，我们从来没有在如此核心业务系统的数据库上使用过 PC Server 和本地硬盘来承载数据库，一直是使用 IBM  小型机和中高端存储设备来解决高性能和高可靠的问题。在更换成 PC Server 和本地硬盘来承载数据库之后，我们就必须面对 PC Server  本身硬件可能存在的不可靠性所带来的 Crash，所以我们必须有一套完善的 HA 切换机制，要比小型机厂商所提供的商业 HA  管理软件更加高效更加自动化更加可控，才能我们降低了设备本身可靠性之后达到原有的可用性要求。</p>
<p>对于一个需要满足 365 *  24 * 7 的核心业务系统来说，肯定是不可能给我们太多时间来进行数据迁移的，所以我们不得不设计出一个对现有系统影响尽可能小的迁移方案，这势必会造成方案的高度复杂化，带来更多的风险。最后的迁移方案要经历如下4个阶段：</p>
<p>1. Oracle 读/写;；MySQL 初始化并增量写<br />
2. Oracle 读/写； MySQL 写<br />
3. Oracle 写； MySQL 读/写<br />
4. Oracle 停访问； MySQL 读/写</p>
<p>当然，也正式由于有如此复杂的方案，才确保了在整个迁移过程中的的停机时间被控制在了10分钟之类。</ul>
<ul>
<li>附属Detail信息迁移至 MySQL</li>
<p>从项目开始，至完成主表拆分结束，已经接近2年了。这2年时间内，数据量一直都在飞涨，这让即使仅仅只是按照主键访问的附表也快无法承受持续增长的 业务压力，附表的拆分也就成了必行之势。由于在原来主表拆分的过程中，整个项目组已经积累了大量的经验，附表拆分过程非常顺利，基本没有出现任何问题。虽 然附表的拆分过程与主表相比除了 1拆16这个阶段外没有减少其他任何环节，但是整个拆分过程也才2个月就全部搞定了。</ul>
<p>这个迁移项目算是彻底完成了，但是我们的迁移之路并不会就此止步，还有很多的系统仍然存在扩展性问题，还有很多的数据库应用等着我们去拆分。</p>
<p>注：同事们还为此送了我们一个虽不太雅但也意思相近的名称 “拆迁队”。</p>
<p>原文出自： <strong><a href="http://isky000.com/">Sky.Jian  –  i Sky000 </a></strong><a href="http://isky000.com/"><br />
</a></p>
<h2><a title="Permanent Link to 核心业务系统数据库平台迁移： Oracle -&gt; MySQL" rel="bookmark" href="http://isky000.com/database/core-databas-system-migration-from-oracle-to-mysql">核心业务系统数据库平台迁移： Oracle -&gt; MySQL</a></h2>
]]></content:encoded>
			<wfw:commentRss>http://www.alidba.net/index.php/archives/432/feed</wfw:commentRss>
		</item>
		<item>
		<title>Alibaba DBA Team 2010/08</title>
		<link>http://www.alidba.net/index.php/archives/425</link>
		<comments>http://www.alidba.net/index.php/archives/425#comments</comments>
		<pubDate>Tue, 10 Aug 2010 11:02:41 +0000</pubDate>
		<dc:creator>grassbell</dc:creator>
		
		<category><![CDATA[大话技术]]></category>

		<guid isPermaLink="false">http://www.alidba.net/?p=425</guid>
		<description><![CDATA[
]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/grassbell/4878866332/" title="Alibaba DBA 2010/8 by Grassbell, on Flickr"><img src="http://farm5.static.flickr.com/4117/4878866332_0bec2c6f96_z.jpg" width="640" height="384" alt="Alibaba DBA 2010/8" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.alidba.net/index.php/archives/425/feed</wfw:commentRss>
		</item>
		<item>
		<title>MySQL Query Cache 小结</title>
		<link>http://www.alidba.net/index.php/archives/423</link>
		<comments>http://www.alidba.net/index.php/archives/423#comments</comments>
		<pubDate>Mon, 05 Jul 2010 03:48:45 +0000</pubDate>
		<dc:creator>sky</dc:creator>
		
		<category><![CDATA[大话技术]]></category>

		<category><![CDATA[MySQL]]></category>

		<category><![CDATA[Query Cache]]></category>

		<guid isPermaLink="false">http://www.alidba.net/?p=423</guid>
		<description><![CDATA[最近经常有人问我 MySQL Query Cache 相关的问题，就整理一点 MySQL Query Cache 的内容，以供参考。
顾名思义，MySQL Query Cache 就是用来缓存和 Query 相关的数据的。具体来说，Query Cache  缓存了我们客户端提交给 MySQL 的 SELECT 语句以及该语句的结果集。大概来讲，就是将 SELECT 语句和语句的结果做了一个 HASH  映射关系然后保存在一定的内存区域中。
在大部分的 MySQL 分发版本中，Query Cache 功能默认都是打开的，我们可以通过调整 MySQL Server  的参数选项打开该功能。主要由以下5个参数构成：

query_cache_limit：允许 Cache 的单条 Query 结果集的最大容量，默认是1MB，超过此参数设置的 Query  结果集将不会被 Cache
query_cache_min_res_unit：设置 Query Cache 中每次分配内存的最小空间大小，也就是每个 Query 的  Cache 最小占用的内存空间大小
query_cache_size：设置 Query Cache  所使用的内存大小，默认值为0，大小必须是1024的整数倍，如果不是整数倍，MySQL 会自动调整降低最小量以达到1024的倍数
query_cache_type：控制 [...]]]></description>
			<content:encoded><![CDATA[<p>最近经常有人问我 MySQL Query Cache 相关的问题，就整理一点 MySQL Query Cache 的内容，以供参考。</p>
<p>顾名思义，MySQL Query Cache 就是用来缓存和 Query 相关的数据的。具体来说，Query Cache  缓存了我们客户端提交给 MySQL 的 SELECT 语句以及该语句的结果集。大概来讲，就是将 SELECT 语句和语句的结果做了一个 HASH  映射关系然后保存在一定的内存区域中。</p>
<p>在大部分的 MySQL 分发版本中，Query Cache 功能默认都是打开的，我们可以通过调整 MySQL Server  的参数选项打开该功能。主要由以下5个参数构成：</p>
<ul>
<li>query_cache_limit：允许 Cache 的单条 Query 结果集的最大容量，默认是1MB，超过此参数设置的 Query  结果集将不会被 Cache</li>
<li>query_cache_min_res_unit：设置 Query Cache 中每次分配内存的最小空间大小，也就是每个 Query 的  Cache 最小占用的内存空间大小</li>
<li>query_cache_size：设置 Query Cache  所使用的内存大小，默认值为0，大小必须是1024的整数倍，如果不是整数倍，MySQL 会自动调整降低最小量以达到1024的倍数</li>
<li>query_cache_type：控制 Query Cache  功能的开关，可以设置为0(OFF),1(ON)和2(DEMAND)三种，意义分别如下：
<ul>
<li> 0(OFF)：关闭 Query Cache 功能，任何情况下都不会使用 Query Cache</li>
<li>1(ON)：开启 Query Cache 功能，但是当 SELECT 语句中使用的 SQL_NO_CACHE 提示后，将不使用Query  Cache</li>
<li>2(DEMAND)：开启 Query Cache 功能，但是只有当 SELECT 语句中使用了 SQL_CACHE 提示后，才使用  Query Cache</li>
</ul>
</li>
<li>query_cache_wlock_invalidate：控制当有写锁定发生在表上的时刻是否先失效该表相关的 Query  Cache，如果设置为 1(TRUE)，则在写锁定的同时将失效该表相关的所有 Query  Cache，如果设置为0(FALSE)则在锁定时刻仍然允许读取该表相关的 Query Cache。</li>
</ul>
<p><strong>Query Cache 如何处理子查询的？</strong><br />
这是我遇到的最为常见的一个问题。其实 Query Cache 是以客户端请求提交的 Query 为对象来处理的，只要客户端请求的是一个  Query，无论这个 Query 是一个简单的单表查询还是多表 Join，亦或者是带有子查询的复杂 SQL，都被当作成一个  Query，不会被分拆成多个 Query 来进行 Cache。所以，存在子查询的复杂 Query  也只会产生一个Cache对象，子查询不会产生单独的Cache内容。UNION[ALL] 类型的语句也同样如此。</p>
<p><strong>Query Cache 是以 block 的方式存储的数据块吗？</strong><br />
不是，Query Cache 中缓存的内容仅仅只包含该 Query  所需要的结果数据，是结果集。当然，并不仅仅只是结果数据，还包含与该结果相关的其他信息，比如产生该 Cache  的客户端连接的字符集，数据的字符集，客户端连接的 Default Database等。</p>
<p><strong>Query Cache 为什么效率会非常高，即使所有数据都可以 Cache 进内存的情况下，有些时候也不如使用 Query  Cache 的效率高？</strong><br />
Query Cache 的查找，是在 MySQL 接受到客户端请求后在对 Query 进行权限验证之后，SQL 解析之前。也就是说，当  MySQL 接受到客户端的SQL后，仅仅只需要对其进行相应的权限验证后就会通过 Query Cache 来查找结果，甚至都不需要经过  Optimizer 模块进行执行计划的分析优化，更不许要发生任何存储引擎的交互，减少了大量的磁盘 IO 和 CPU 运算，所以效率非常高。</p>
<p><strong>客户端提交的 SQL 语句大小写对 Query Cache 有影响吗？</strong><br />
有，由于 Query Cache 在内存中是以 HASH 结构来进行映射，HASH 算法基础就是组成 SQL 语句的字符，所以必须要整个 SQL  语句在字符级别完全一致，才能在 Query Cache 中命中，即使多一个空格也不行。</p>
<p><strong>一个 SQL 语句在 Query Cache 中的内容，在什么情况下会失效？</strong><br />
为了保证 Query Cache 中的内容与是实际数据绝对一致，当表中的数据有任何变化，包括新增，修改，删除等，都会使所有引用到该表的 SQL 的  Query Cache 失效。</p>
<p><strong>为什么我的系统在开启了 Query Cache 之后整体性能反而下降了？</strong><br />
当开启了 Query Cache 之后，尤其是当我们的 query_cache_type 参数设置为 1 以后，MySQL 会对每个  SELECT 语句都进行 Query Cache 查找，查找操作虽然比较简单，但仍然也是要消耗一些 CPU 运算资源的。而由于 Query  Cache 的失效机制的特性，可能由于表上的数据变化比较频繁，大量的 Query Cache 频繁的被失效，所以 Query Cache  的命中率就可能比较低下。所以有些场景下，Query Cache 不仅不能提高效率，反而可能造成负面影响。</p>
<p><strong>如何确认一个系统的 Query Cache 的运行是否健康，命中率如何，设置量是否足够？</strong><br />
MySQL 提供了一系列的 Global Status 来记录 Query Cache 的当前状态，具体如下：</p>
<ul>
<li>Qcache_free_blocks：目前还处于空闲状态的 Query Cache 中内存 Block 数目</li>
<li>Qcache_free_memory：目前还处于空闲状态的 Query Cache 内存总量</li>
<li>Qcache_hits：Query Cache 命中次数</li>
<li>Qcache_inserts：向 Query Cache 中插入新的 Query Cache 的次数，也就是没有命中的次数</li>
<li>Qcache_lowmem_prunes：当 Query Cache 内存容量不够，需要从中删除老的 Query Cache 以给新的  Cache 对象使用的次数</li>
<li>Qcache_not_cached：没有被 Cache 的 SQL 数，包括无法被 Cache 的 SQL 以及由于  query_cache_type 设置的不会被 Cache 的 SQL</li>
<li>Qcache_queries_in_cache：目前在 Query Cache 中的 SQL 数量</li>
<li>Qcache_total_blocks：Query Cache 中总的 Block 数量</li>
</ul>
<p>可以根据这几个状态计算出 Cache 命中率，计算出 Query Cache 大小设置是否足够，总的来说，我个人不建议将 Query  Cache 的大小设置超过256MB，这也是业界比较常用的做法。<br />
<strong><br />
MySQL Cluster 是否可以使用 Query Cache？</strong><br />
其实在我们的生产环境中也没有使用 MySQL Cluster，所以我也没有在 MySQL Cluster 环境中使用 Query Cache  的实际经验，只是 MySQL 文档中说明确实可以在 MySQL Cluster 中使用 Query Cache。从 MySQL Cluster  的原理来分析，也觉得应该可以使用，毕竟 SQL 节点和数据节点比较独立，各司其职，只是 Cache 的失效机制会要稍微复杂一点。</p>
<p>原文出自：<a title="Permanent Link to MySQL Query Cache 小结" rel="bookmark" href="http://isky000.com/database/mysql-query-cache-summary">MySQL  Query Cache 小结</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.alidba.net/index.php/archives/423/feed</wfw:commentRss>
		</item>
		<item>
		<title>ORACLE BITMAP INDEX</title>
		<link>http://www.alidba.net/index.php/archives/416</link>
		<comments>http://www.alidba.net/index.php/archives/416#comments</comments>
		<pubDate>Mon, 24 May 2010 07:29:19 +0000</pubDate>
		<dc:creator>vogts</dc:creator>
		
		<category><![CDATA[大话技术]]></category>

		<guid isPermaLink="false">http://www.alidba.net/?p=416</guid>
		<description><![CDATA[ORACLE BITMAP INDEX]]></description>
			<content:encoded><![CDATA[<div>ORACLE的bitmap索引，我们用的很少。在我们的常理认识当中，我们用的最多就是类似性别，类型这种属性的字段，因为他们字段的种类很少。其实 BITMAP还是有很多优势以及一些特性的。</p>
<p>首先在传统的INDEX里，我们在索引的存储上，一般是分为：header+index  length+index value+rowid组成。如图：</p>
<div style="text-align: left;"><a href="http://www.alidba.net/wp-content/uploads/2010/05/2010-05-24_142946.png"><img class="alignnone size-full wp-image-417" src="http://www.alidba.net/wp-content/uploads/2010/05/2010-05-24_142946.png" alt="2010-05-24_142946" width="298" height="189" /></a></div>
<p>bitmap的存储结果相对来说，复杂一点。 bitmap  不存储rowid。那么rowid存储在哪里呢？答：每一个bitmap的头部，都存储了rowid的启示位置与结束位置。ORACLE通过自己的内部算 法，算出来相应的ROWID。<br />
位图中的每一位，都记录是否有值。<br />
如表的记录是这样存储的：</p>
<table id="vgvf" border="1" cellspacing="0" cellpadding="3">
<tbody>
<tr>
<td width="100%">row-value</td>
</tr>
<tr>
<td width="100%">male</td>
</tr>
<tr>
<td width="100%">female</td>
</tr>
<tr>
<td width="100%">female</td>
</tr>
<tr>
<td width="100%">male</td>
</tr>
</tbody>
</table>
<p>那么对应的bitmap则是这样存储的：</p>
<table id="csin" border="1" cellspacing="0" cellpadding="3" width="100%">
<tbody>
<tr>
<td width="50%">rowid的启示位置与结束位置</td>
<td width="50%">rowid的启示位置与结束位置</td>
</tr>
<tr>
<td width="50%">male</td>
<td width="50%">female</td>
</tr>
<tr>
<td width="50%">1</td>
<td width="50%">0</td>
</tr>
<tr>
<td width="50%">0</td>
<td width="50%">1</td>
</tr>
<tr>
<td width="50%">0</td>
<td width="50%">1</td>
</tr>
<tr>
<td width="50%">1</td>
<td width="50%">0</td>
</tr>
</tbody>
</table>
<p>由 此可见，存储的空间大大的节省了，另外带来的收益就是扫描的BLOCK也大大减少了。</p>
<p>如果查找性别是male的数据，ORACLE只会去 搜索MALE这一列，然后是1的记录，返回即可。</p>
<p>如果是针对BITMAP字段本身做OR,AND这样的查询，那么ORACLE会在 BITMAP索引内部，先做一次判断，找出符合结果的，再去计算ROWID，最后给出相应的VALUE，示意图如下：</p>
<div style="text-align: left;"><a href="http://www.alidba.net/wp-content/uploads/2010/05/dwhsg093.gif"><img class="alignnone size-full wp-image-418" src="http://www.alidba.net/wp-content/uploads/2010/05/dwhsg093.gif" alt="dwhsg093" width="600" height="176" /></a></div>
<p><strong>bitmap join index</strong><br />
bitmap  join  index，它的特点就是将多张表的JOIN结果，存储在一个索引里面，然后使用BITMAP的形式进行存储。图难画了，请见谅，改天有空的时候，再把图 补上。这个对于类似DW那样的多表join效率提高很明显。<br />
我今天做了一个测试，是用3张表join来做的，原来的SQL是这样的：<br />
test@DB&gt;                        select wt_cust.company_name,wt_cust.gmt_create<br />
2   from  wt_cust,wt_CUST_EXT ,wt_CUST_BOOK<br />
3  where  wt_cust.id=wt_CUST_EXT.Cust_Id<br />
4  and  wt_CUST_BOOK.Cust_Id=wt_cust.id;</p>
<p>58 rows selected.</p>
<p>Elapsed:  00:00:00.01</p>
<p>Execution Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
|  Id  | Operation                     | Name                          |  Rows  | Bytes | Cost (%CPU)|<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
|    0 | SELECT STATEMENT              |                               |     54 |  2484 |   179   (0)|<br />
|   1 |  NESTED LOOPS                  |                               |    54 |  2484 |   179   (0)|<br />
|   2  |   NESTED LOOPS                |                               |   177  |  7257 |   179   (0)|<br />
<span style="color: #ff0000;">|   3 |    INDEX FULL SCAN            |  wt_CUST_BOOK_UK     |   177 |  1062 |     1   (0)|<br />
|   4 |     TABLE ACCESS BY INDEX ROWID| wt_CUST             |     1 |    35  |     2   (0)|<br />
|*  5 |     INDEX UNIQUE SCAN         |  wt_CUST_PK          |     1 |       |     1   (0)|<br />
|*  6 |    INDEX RANGE SCAN            | wt_CUST_EXT_CID_IND |     1 |     5  |     0   (0)|</span><br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>一 个3表join，效率很差。如果我们创建BITMAP JOIN INDEX则可以避免这种情况的发生：<br />
test@DB&gt;CREATE  BITMAP INDEX cust_wt_test<br />
2  ON      wt_cust(wt_cust.company_name)<br />
3  FROM    wt_cust,wt_CUST_EXT ,wt_CUST_BOOK<br />
4  WHERE   wt_cust.id=wt_CUST_EXT.Cust_Id<br />
5  and  wt_CUST_BOOK.Cust_Id=wt_cust.id<br />
6  tablespace test_ind   ;</p>
<p>Index created.</p>
<p>Elapsed: 00:00:00.08<br />
再来看看SQL的执行计划：<br />
xx@DB&gt;select   wt_cust.company_name,wt_cust.gmt_create<br />
2   from  wt_cust,wt_CUST_EXT ,wt_CUST_BOOK<br />
3  where  wt_cust.id=wt_CUST_EXT.Cust_Id<br />
4  and  wt_CUST_BOOK.Cust_Id=wt_cust.id;</p>
<p>58 rows selected.</p>
<p>Elapsed:  00:00:00.00</p>
<p>Execution Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
|  Id  | Operation                    | Name              | Rows  | Bytes |  Cost (%CPU)|<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
|    0 | SELECT STATEMENT             |                   |  1834K|     61M|   219K  (1)|<br />
|   1 |  TABLE ACCESS BY INDEX ROWID | wt_CUST  |  1834K|    61M|   219K  (1)|<br />
|   2 |   BITMAP CONVERSION TO  ROWIDS|                   |       |       |            |<br />
<span style="color: #ff0000;">|   3 |    BITMAP INDEX FULL SCAN    | CUST_WT_TEST       |       |       |            |</span><br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</p>
<p>请 着重注意红色部分。逻辑读大大降低！！<br />
BTW：<br />
我觉得我们除了传统的NESTLOOP,MERGE JOIN,HASH  JOIN。这样看来又多了一种优化JOIN的方式。</p>
<p>总结：<br />
bitmap我们可能平时使用的不多，但是觉得它在特殊的应用场景，还 是有优势的。bitmap join index更是一种多表JOIN的新方式，很有意思。</p></div>
]]></content:encoded>
			<wfw:commentRss>http://www.alidba.net/index.php/archives/416/feed</wfw:commentRss>
		</item>
		<item>
		<title>在Vmware上安装Oracle 11gR2 的安装简易手册</title>
		<link>http://www.alidba.net/index.php/archives/413</link>
		<comments>http://www.alidba.net/index.php/archives/413#comments</comments>
		<pubDate>Thu, 20 May 2010 02:54:07 +0000</pubDate>
		<dc:creator>jametong</dc:creator>
		
		<category><![CDATA[大话技术]]></category>

		<category><![CDATA[installation]]></category>

		<category><![CDATA[oracle 11gr2]]></category>

		<category><![CDATA[vmware]]></category>

		<guid isPermaLink="false">http://www.alidba.net/?p=413</guid>
		<description><![CDATA[有感于今天内部被问到的一个问题
1. 运行如下的rpm命令,找到安装Oracle需要而没有安装的rpm包.并mount Redat安装盘安装这些包.

rpm -qv binutils-2.17.50.0.6 \
compat-libstdc++-33-3.2.3 \
elfutils-libelf-0.125 \
elfutils-libelf-devel-0.125 \
elfutils-libelf-devel-static-0.125 \
gcc-4.1.2 \
gcc-c++-4.1.2 \
glibc-2.5-24 \
glibc-common-2.5 \
glibc-devel-2.5 \
glibc-headers-2.5 \
kernel-headers-2.6.18  \
ksh-20060214 \
libaio-0.3.106 \
libgcc-4.1.2 \
libgomp-4.1.2 \
libstdc++-4.1.2  \
libstdc++-devel-4.1.2 \
make-3.81 \
sysstat-7.0.2 \
libaio-devel-0.3.106  \
unixODBC-2.2.11  \
unixODBC-devel-2.2.11
mkdir /media/cdrom/
mount -t iso9660 /dev/cdrom /media/cdrom/
cd /media/cdrom/Server/
rpm -ivh sysstat-7.0.2-1.el5.i386.rpm libaio-devel-0.3.106-3.2.i386.rpm unixODBC-2.2.11-7.1.i386.rpm unixODBC-devel-2.2.11-7.1.i386.rpm

2. 关闭大部分无用的服务(可能因人因环境而异,这只是我的个人喜好).

chkconfig NetworkManager --level 2345 off
chkconfig NetworkManagerDispatcher --level 2345 off
chkconfig acpid --level 2345 off
chkconfig [...]]]></description>
			<content:encoded><![CDATA[<p><em>有感于今天内部被问到的一个问题</em></p>
<p><strong>1. 运行如下的rpm命令,找到安装Oracle需要而没有安装的rpm包.并mount Redat安装盘安装这些包.</strong></p>
<pre>
rpm -qv binutils-2.17.50.0.6 \
compat-libstdc++-33-3.2.3 \
elfutils-libelf-0.125 \
elfutils-libelf-devel-0.125 \
elfutils-libelf-devel-static-0.125 \
gcc-4.1.2 \
gcc-c++-4.1.2 \
glibc-2.5-24 \
glibc-common-2.5 \
glibc-devel-2.5 \
glibc-headers-2.5 \
kernel-headers-2.6.18  \
ksh-20060214 \
libaio-0.3.106 \
libgcc-4.1.2 \
libgomp-4.1.2 \
libstdc++-4.1.2  \
libstdc++-devel-4.1.2 \
make-3.81 \
sysstat-7.0.2 \
libaio-devel-0.3.106  \
unixODBC-2.2.11  \
unixODBC-devel-2.2.11
mkdir /media/cdrom/
mount -t iso9660 /dev/cdrom /media/cdrom/
cd /media/cdrom/Server/
rpm -ivh sysstat-7.0.2-1.el5.i386.rpm libaio-devel-0.3.106-3.2.i386.rpm unixODBC-2.2.11-7.1.i386.rpm unixODBC-devel-2.2.11-7.1.i386.rpm
</pre>
<p><strong>2. 关闭大部分无用的服务(可能因人因环境而异,这只是我的个人喜好).</strong></p>
<pre>
chkconfig NetworkManager --level 2345 off
chkconfig NetworkManagerDispatcher --level 2345 off
chkconfig acpid --level 2345 off
chkconfig apmd --level 2345 off
chkconfig auditd --level 2345 off
chkconfig avahi-dnsconfd --level 2345 off
chkconfig bluetooth --level 2345 off
chkconfig capi --level 2345 off
chkconfig conman --level 2345 off
chkconfig cpuspeed --level 2345 off
chkconfig cups --level 2345 off
chkconfig dhcdbd --level 2345 off
chkconfig dund --level 2345 off
chkconfig firstboot --level 2345 off
chkconfig haldaemon --level 2345 off
chkconfig hidd --level 2345 off
chkconfig ip6tables --level 2345 off
chkconfig ipmi --level 2345 off
chkconfig iptables --level 2345 off
chkconfig irda --level 2345 off
chkconfig isdn --level 2345 off
chkconfig kdump --level 2345 off
chkconfig kudzu --level 2345 off
chkconfig lvm2-monitor --level 2345 off
chkconfig mcstrans --level 2345 off
chkconfig mdmonitor --level 2345 off
chkconfig mdmpd --level 2345 off
chkconfig messagebus --level 2345 off
chkconfig microcode_ctl --level 2345 off
chkconfig multipathd --level 2345 off
chkconfig netconsole --level 2345 off
chkconfig netfs --level 2345 off
chkconfig netplugd --level 2345 off
chkconfig nfs --level 2345 off
chkconfig nfslock --level 2345 off
chkconfig nscd --level 2345 off
chkconfig ntpd --level 2345 off
chkconfig pand --level 2345 off
chkconfig pcscd --level 2345 off
chkconfig portmap --level 2345 off
chkconfig psacct --level 2345 off
chkconfig rdisc --level 2345 off
chkconfig readahead_later --level 2345 off
chkconfig restorecond --level 2345 off
chkconfig rhnsd --level 2345 off
chkconfig rpcgssd --level 2345 off
chkconfig rpcidmapd --level 2345 off
chkconfig rpcsvcgssd --level 2345 off
chkconfig saslauthd --level 2345 off
chkconfig sendmail --level 2345 off
chkconfig setroubleshoot --level 2345 off
chkconfig smartd --level 2345 off
chkconfig vncserver --level 2345 off
chkconfig vsftpd --level 2345 off
chkconfig wdaemon --level 2345 off
chkconfig winbind --level 2345 off
chkconfig wpa_supplicant --level 2345 off
chkconfig ypbind --level 2345 off
</pre>
<p><strong>3. 修改系统参数(这只是我的测试环境,具体环境需要做适应性的调整,而且我这个虚拟机,毋需考虑BigPage,生产环境可能需要考虑,特别是64位环境下的11g环境).</strong></p>
<pre>
--修改/etc/sysctl.conf
fs.aio-max-nr = 1048576
fs.file-max = 6815744
kernel.shmall = 2097152
kernel.shmmax = 536870912
kernel.shmmni = 4096
kernel.sem = 250 32000 100 128
net.ipv4.ip_local_port_range = 9000 65500
net.core.rmem_default = 262144
net.core.rmem_max = 4194304
net.core.wmem_default = 262144
net.core.wmem_max = 1048586

--修改完毕后, 运行sysctl -p使其生效.
</pre>
<p><strong>4. 添加用户/组信息.</strong></p>
<pre>
groupadd -g 501 oinstall
groupadd -g 502 dba
groupadd -g 503 oper
groupadd -g 504 asmadmin
groupadd -g 505 asmdba
groupadd -g 506 asmoper

useradd -g oinstall -G dba,oper,asmdba oracle
useradd -g oinstall -G asmadmin,asmdba,asmoper grid
</pre>
<p><strong>5. 修改安全配置信息,</strong></p>
<li>  1) . Add the following lines to the /etc/security/limits.conf file: (the following example shows the software account owner oracle):</li>
<pre>

oracle              soft    nproc   2047
oracle              hard    nproc   16384
oracle              soft    nofile  1024
oracle              hard    nofile  65536

grid              soft    nproc   2047
grid              hard    nproc   16384
grid              soft    nofile  1024
grid              hard    nofile  65536
</pre>
<li>  2). Add or edit the following line in the /etc/pam.d/login file, if it does not already exist:</li>
<pre>
session    required     pam_limits.so
</pre>
<p><strong>6. 修改/etc/profile 信息,修改Oracle/grid用户登陆后的系统权限.</strong><br />
For the Bourne, Bash, or Korn shell, add the following lines to the /etc/profile file (or the file<br />
on<br />
  SUSE Linux Enterprise Server systems /etc/profile.local):</p>
<pre>

if [ $USER = "oracle" ]; then
  if [ $SHELL = "/bin/ksh" ]; then
    ulimit -p 16384
    ulimit -n 65536
  else
    ulimit -u 16384 -n 65536
  fi
  umask 022
fi

if [ $USER = "grid" ]; then
  if [ $SHELL = "/bin/ksh" ]; then
    ulimit -p 16384
    ulimit -n 65536
  else
    ulimit -u 16384 -n 65536
  fi
  umask 022
fi
</pre>
<p><strong>7. 创建基本的安装目录.并赋予其权限.</strong></p>
<pre>
mkdir -p /opt/app/
mkdir -p /opt/app/oracle/products/11.2.0/
chown -R oracle:oinstall /opt/app/oracle

mkdir -p /opt/app/grid/products/11.2.0/
chown -R grid:oinstall /opt/app/grid

chown grid:oinstall /opt/
chown grid:oinstall /opt/app/
chown grid:oinstall /opt/app/oracle/
</pre>
<p><strong>8. 修改用户profile信息.</strong></p>
<li>1). 修改grid用户的profile文件/home/grid/.bash_profile</li>
<pre>
export ORACLE_BASE=/opt/app/oracle
export ORACLE_HOME=/opt/app/grid/products/11.2.0
export ORACLE_SID=+ASM1
CLASSPATH=$ORACLE_HOME/JRE:$ORACLE_HOME/jlib:$ORACLE_HOME/rdbms/jlib:$ORACLE_HOME/network/jlib
export ORACLE_BASE ORACLE_HOME ORACLE_SID ORA_NLS33 PATH  CLASSPATH TNS_ADMIN

PATH=$ORACLE_HOME/bin:/usr/bin:/etc:/usr/bin/X11:/usr/ccs/bin:/usr/bin:/etc:/usr/sbin:/usr/ucb:/usr/bin/X11:/sbin:/usr/java14/jre/bin:/usr/java14/bin:/usr/local/bin:.:$PATH
export  PATH
export PATH=$PATH:$ORACLE_HOME/OPatch

# ORACLE_TERM=xterm; export ORACLE_TERM
NLS_LANG=AMERICAN_AMERICA.US7ASCII; export NLS_LANG

LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib:/usr/openwin/lib
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/td/lib:/usr/ucblib:/usr/local/lib
export LD_LIBRARY_PATH
export NLS_DATE_FORMAT="YYYY-MM-DD HH24:MI:SS"
export UDUMP=/opt/oracle/admin/forum/udump
export BDUMP=/opt/oracle/admin/forum/bdump
export SQLPATH=$ORACLE_HOME/sqlplus/admin:~/admin/sql/:~/admin/mysql
alias sql='sqlplus /nolog'
alias lm='ls -al'
export DISPLAY=192.168.68.1:0.0
</pre>
<li>2). 修改Oracle用户profile信息.</li>
<pre>

export ORACLE_BASE=/opt/app/oracle
export ORACLE_HOME=/opt/app/grid/products/11.2.0
export ORACLE_SID=rac1
CLASSPATH=$ORACLE_HOME/JRE:$ORACLE_HOME/jlib:$ORACLE_HOME/rdbms/jlib:$ORACLE_HOME/network/jlib
export ORACLE_BASE ORACLE_HOME ORACLE_SID ORA_NLS33 PATH  CLASSPATH TNS_ADMIN

PATH=$ORACLE_HOME/bin:/usr/bin:/etc:/usr/bin/X11:/usr/ccs/bin:/usr/bin:/etc:/usr/sbin:/usr/ucb:/usr/bin/X11:/sbin:/usr/java14/jre/bin:/usr/java14/bin:/usr/local/bin:.:$PATH
export  PATH
export PATH=$PATH:$ORACLE_HOME/OPatch

# ORACLE_TERM=xterm; export ORACLE_TERM
NLS_LANG=AMERICAN_AMERICA.US7ASCII; export NLS_LANG

LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib:/usr/openwin/lib
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/td/lib:/usr/ucblib:/usr/local/lib
export LD_LIBRARY_PATH
export NLS_DATE_FORMAT="YYYY-MM-DD HH24:MI:SS"
export UDUMP=/opt/oracle/admin/forum/udump
export BDUMP=/opt/oracle/admin/forum/bdump
export SQLPATH=$ORACLE_HOME/sqlplus/admin:~/admin/sql/:~/admin/mysql
alias sql='sqlplus /nolog'
alias lm='ls -al'
</pre>
<p><strong>9. 修改/etc/hosts信息,配置RAC信息.</strong></p>
<pre>

192.168.68.128    rac1-priv.localdomain rac1-priv
192.168.68.129    rac2-priv.localdomain rac2-priv

192.168.130.128    rac1.localdomain rac1
192.168.130.129    rac2.localdomain rac2

192.168.130.200   rac-cluster
192.168.130.210   rac1-vip.localdomain rac1-vip
192.168.130.220   rac2-vip.localdomain rac2-vip
</pre>
<p><strong>10. 配置两台主机的ssh 通道.</strong><br />
分别在root/oracle/grid用户下运行下述命令.</p>
<pre>

ssh-keygen -b 1024 -t dsa
</pre>
<p><strong>11. 关闭两个VM节点, 为其添加一块基于Nat的网卡,以及新增两块磁盘(一块作为OCR/Voting Disk用,一块作为SharedStorage使用).</strong><br />
修改VM文件的配置,新增的磁盘配置为.</p>
<pre>

disk.locking = "FALSE"
diskLib.dataCacheMaxSize = "0"
diskLib.dataCacheMaxReadAheadSize = "0"
diskLib.dataCacheMinReadAheadSize = "0"
diskLib.dataCachePageSize = "4096"
diskLib.maxUnsyncedWrites = "0"

scsi1.present = "TRUE"
scsi1.virtualDev = "lsilogic"
scsi1.sharedBus = "VIRTUAL"

scsi1:0.redo = ""
scsi1:0.present = "TRUE"
scsi1:0.fileName = "E:\vm\SharedDisk\OCRDisk.vmdk"
scsi1:0.mode = "independent-persistent"
scsi1:0.deviceType = "disk"

scsi1:1.redo = ""
scsi1:1.present = "TRUE"
scsi1:1.fileName = "E:\vm\SharedDisk\RacShareDisk.vmdk"
scsi1:1.mode = "independent-persistent"
scsi1:1.deviceType = "disk"
</pre>
<p><strong>12. 运行下面的脚本给/dev/sdb;/dev/sdc 进行分区</strong></p>
<pre>

fdisk /dev/sdc &lt;&lt;_END_
n
e
1

n
l
1
128
n
l

256
n
l

384
n
l

512
n
l

640
n
l

p
w
_END_
</pre>
<p><strong>13. 在/etc/udev/rules.d/50-udev.rules中添加下面这行配置.</strong></p>
<pre>

KERNEL=="sd[bc]*",OWNER="grid",GROUP="oinstall",MODE="0660",OPTIONS="last_rule"
</pre>
<p>并运行/sbin/start_udev使其权限修改生效,否则每次Os重启,文件的权限都会被改成root:disk</p>
]]></content:encoded>
			<wfw:commentRss>http://www.alidba.net/index.php/archives/413/feed</wfw:commentRss>
		</item>
		<item>
		<title>Linux一些页的东西</title>
		<link>http://www.alidba.net/index.php/archives/410</link>
		<comments>http://www.alidba.net/index.php/archives/410#comments</comments>
		<pubDate>Thu, 06 May 2010 15:12:23 +0000</pubDate>
		<dc:creator>vogts</dc:creator>
		
		<category><![CDATA[大话技术]]></category>

		<guid isPermaLink="false">http://www.alidba.net/?p=410</guid>
		<description><![CDATA[LINUX PAGE 页]]></description>
			<content:encoded><![CDATA[<div>在Linux世界里，分为Page cache,Buffer  cache两个层面。其中page cache包含了buffer cache，内存只和page cache交互。</p>
<p>标准的LINUX总 是假定处理器有三级页表，分别为页目录表（PGD），中间页目录表（PMD）和页表(PTE)。如果程序在进行物理地址转换的时候，中是通过页目录表来索 引中间页目录表，再通过中间页目录表来索引页表，从而查找到某页与内存BLOCK块的对应关系。我把书上的图，拍下来了，哈：</p>
<div style="text-align: left;"><img style="height: 239px; width: 636px;" src="https://docs.google.com/File?id=dc4njs9z_9hr5mtpjp_b" alt="" /></div>
</div>
<div></div>
<div>我们平时只说，page in,page out。file,page cahe,buffer  cache,block的关系如下图：</div>
<div>
<div style="text-align: left;"><img src="https://docs.google.com/File?id=dc4njs9z_3dxm4xtft_b" alt="" /></div>
<p>我们主要讨论下 linux的页的生命：</p></div>
<div></div>
<div>在讨论page之前，必须要提及 LINUX的几个关键进程：  kscand, kswapd, kupdated, bdflush. 他们负责LINUX的内存管理。</div>
<div></div>
<div>一般内存的一页，生命周期如下图：</div>
<div style="text-align: left;"><img src="https://docs.google.com/File?id=dc4njs9z_4ccv56tc8_b" alt="" /></div>
<div>free &#8211;  在系统启动以后，初始化状态均为FREE。</div>
<div></div>
<div>active －－ 当前被OS使用或者用户进程所使用的状态，均为active。</div>
<div></div>
<div>inactive dirty（脏数据） －－  当数据被修改过以后，kscand进程会周期性的对内存中的数据进行扫描。如果最近被访问过了，计数器就会加1，否则被减1。如果kscand发现计数器 是0的时候，就会把该页，放到非队列（inactive laundry）里去了。</div>
<div></div>
<div>inactive laundry（非活动队列） －－ 当被放到inactive  laundry里的时候，OS才真正的进行I/O操作，写入磁盘。</div>
<div></div>
<div>inactive clean －－ 意味着数据已经被sync到了本地磁盘，该页也已经标示为free。</div>
<div></div>
<div>另：</div>
<div>如果想自己强行把脏数据，写到磁盘 上，就使用“sync”命令。</div>
<div></div>
<div>个人总结：</div>
<div>今天看了一个晚上这方面的书和文档，感觉LINUX的机制和ORACLE大同小异啊。其实这个世界什么东西，都大同小异啊，关键 是你要想明白，计算机世界永远离不开if,else,for;就如同汽车世界永远离不开发动机，地盘，等等。LINUX本身也有LRU,只是有的地方叫 “Buddy Allocator”。</div>
]]></content:encoded>
			<wfw:commentRss>http://www.alidba.net/index.php/archives/410/feed</wfw:commentRss>
		</item>
		<item>
		<title>Oracle高可用架构</title>
		<link>http://www.alidba.net/index.php/archives/406</link>
		<comments>http://www.alidba.net/index.php/archives/406#comments</comments>
		<pubDate>Fri, 19 Mar 2010 08:10:27 +0000</pubDate>
		<dc:creator>jametong</dc:creator>
		
		<category><![CDATA[大话技术]]></category>

		<category><![CDATA[dataguard]]></category>

		<category><![CDATA[maa]]></category>

		<category><![CDATA[Maximum Availability Architecture]]></category>

		<category><![CDATA[RAC]]></category>

		<guid isPermaLink="false">http://www.alidba.net/?p=406</guid>
		<description><![CDATA[今天在Uwe Hesse的Blog上看到这篇文章,感觉很不错,简要地描述Oracle MAA架构的所有相关产品,虽然之前就有接触所有这些解决方案,但解释的如此清楚明了的还是第一次看到,特将其翻译如下. 原文: Oracle Database HA Architecture
Oracle高可用架构
作者: Uwe Hesse, 译者: Jametong
Oracle高可用架构是我所讲课程里的一个热门话题.本文尝试对此话题做一个总体的说明,内容涵盖&#8221;普通的&#8221;单实例数据库,DataGuard,RAC以及扩展RAC(有时也被称为&#8221;伸展集群&#8221;).Rac与Dataguard组合在一起就是Oracle公司推广的最大可用性架构(Maximum Availability Architecture,MAA).除这些Oracle的HA解决方案外,我还会简单介绍一个第三方的HA解决方案(远程镜像,Remote Mirroring).我不准备深入介绍所有这些解决方案的细节,而只是想做出一点区分的工作,并简要介绍它们各自的优势以及可能的缺陷.
首先,我们将考察目前为止仍然是应用最为广泛的Oracle数据库架构:单实例数据库.一个Oracle数据库总是由一个数据库(由数据文件,在线重做日志控制文件组成)与一个实例(有内存结构,比如数据库高速缓冲区;以及后台进程,例如数据库写进程)组成.如果我们有一个数据库以及多个访问这个数据库的实例,这就是一个RAC.如果只有一个实例访问这个数据库,就是单实例数据库.下图是一个所有组件都存储在一个服务器上的简单安装版本:

将数据库文件放置在SAN(存储区域网络)的配置也是目前比较常见的配置,如下图所示:

从高可用的角度来看,这个架构是非常脆弱的:服务器A与服务器B都是单点故障,数据库A与数据库B也都是单点故障.从而这些服务器所在的站点也是单点故障.这样,只要其中一个单点发生故障,整个数据库将不可用.一个&#8221;普通的&#8221;RAC就是为了解决其中的服务器单点故障的,如下图所示:

如果两个服务器的其中一个发生故障,数据库C将仍然可用.当然,使用RAC并不仅仅是为了实现HA.在使用RAC的其它的理由中,一个比较可靠的理由是为了实现伸缩性(Scalability):如果应用需求在将来出现增长,我们可以通过添加新的节点(Node)到集群中来解决.另外,通过使用RAC我们还可以选择使用服务管理(Service-Management)与负载均衡(Load Balance).简言之,RAC不仅仅是HA,在此详述其它原因已经超出本文的范畴了.从HA的视角看,使用RAC的缺陷是:数据库C以及相应的站点C是单点.如果站点C发生故障(比如火灾),数据库C将不可用.因此,将数据库伸展到两个站点就成为我们的选择了,这也是通常所说的扩展RAC.

现在,这两个站点就不再是单点了.数据库D是在两个站点之间做镜像的.这个架构的缺陷是两个站点之间的网络连接的成本,如果两个站点之间的距离比较远的话.这很关键,因为需要镜像的数据量会非常大.实际上,这使得两个站点之间的距离局限于几公里以内,而这与想要实现的灾难保护目标之间有冲突.这时,Dataguard就隆重登场了:利用DataGuard,我们很容易就可以实现长距离的灾难保护,因为,此时我们不再需要传输所有的数据量,而仅仅需要传输(相对小)的重做日志.在下图中,每个服务器都像上面的服务器A与服务器B一样,只有一个实例:

备用数据库由来自主数据库的重做日志. 当主库发生故障时,我们可以失败切换(Failover)到备库上并继续有效工作.这个失败切换工作可以由一个Observer(观察员程序,通常称为快速启动失败切换,Fast-Start Failover)自动实现.两个站点之间的距离达到几千公里(依赖于重做日志的传输策略与保护级别(protection level)).如果我们将RAC与Dataguard集合起来,我们就实现了MAA.显然,MAA是一个昂贵的解决方案,不过它也同时享有RAC与Dataguard的所有好处.
远程镜像是一个广受欢迎的第三方HA解决方案.总体上,它的架构与下图类似:

这时,也没有哪个站点是单点的,类似于使用扩展RAC架构.这个解决方案的缺陷是:站点间的距离也是严格受限制的,理由与扩展RAC架构类似.同时,在镜像进行的时候,第二个站点是无法提供服务的,这一点与上述的Oracle提供的HA解决方案不同.使用RAC时,所有的服务器与相应的站点都可以提供服务.哪怕是使用Dataguard,备用数据库也不仅仅是等待主库发生故障.除此之外,它还可以提供只读访问服务,这将可以有效降低主库的负载.

上图展示了Oracle 11g的新特性&#8221;物理备用数据库上的实时查询&#8221;.在恢复过程中时,备用数据库也在同时提供只读访问.另外,还可以在物理备库(Physical Standby)上做离线备份(OffLoad Backup).
附注:
其实还有另外一种可选择的架构. 基于Data Guard与单实例的一个结合.
类似于上面介绍的远程Data Guard方案, 做了一点修正: 将当前主库的一组Redo 日志放到远程(当然也受限于距离所产生的San 访问延时).
]]></description>
			<content:encoded><![CDATA[<blockquote><p>今天在Uwe Hesse的Blog上看到这篇文章,感觉很不错,简要地描述Oracle MAA架构的所有相关产品,虽然之前就有接触所有这些解决方案,但解释的如此清楚明了的还是第一次看到,特将其翻译如下. 原文: <a href="http://uhesse.wordpress.com/oracle-database-ha-architecture/">Oracle Database HA Architecture</a></p></blockquote>
<p><strong>Oracle高可用架构</strong><br />
作者: <a href="http://uhesse.wordpress.com/">Uwe Hesse</a>, 译者: <a href="http://www.dbthink.com/">Jametong</a><br />
Oracle高可用架构是我所讲课程里的一个热门话题.本文尝试对此话题做一个总体的说明,内容涵盖&#8221;普通的&#8221;单实例数据库,DataGuard,RAC以及扩展RAC(有时也被称为&#8221;伸展集群&#8221;).Rac与Dataguard组合在一起就是Oracle公司推广的最大可用性架构(<a href="http://www.oracle.com/technology/deploy/availability/htdocs/maa.htm">Maximum Availability Architecture,</a>MAA).除这些Oracle的HA解决方案外,我还会简单介绍一个第三方的HA解决方案(远程镜像,Remote Mirroring).我不准备深入介绍所有这些解决方案的细节,而只是想做出一点区分的工作,并简要介绍它们各自的优势以及可能的缺陷.<br />
首先,我们将考察目前为止仍然是应用最为广泛的Oracle数据库架构:单实例数据库.一个Oracle数据库总是由一个数据库(由数据文件,在线重做日志控制文件组成)与一个实例(有内存结构,比如数据库高速缓冲区;以及后台进程,例如数据库写进程)组成.如果我们有一个数据库以及多个访问这个数据库的实例,这就是一个RAC.如果只有一个实例访问这个数据库,就是单实例数据库.下图是一个所有组件都存储在一个服务器上的简单安装版本:<br />
<img src="http://lh3.ggpht.com/_Tj8VUwhrzbg/S6Mog-C4GOI/AAAAAAAAAJc/BHT6vkdJPBs/singleinstance1.gif"/><br />
将数据库文件放置在SAN(存储区域网络)的配置也是目前比较常见的配置,如下图所示:<br />
<img src="http://lh5.ggpht.com/_Tj8VUwhrzbg/S6MohF2tLPI/AAAAAAAAAJg/Z5HOO1nLm0A/singleinstance2.gif"/><br />
从高可用的角度来看,这个架构是非常脆弱的:服务器A与服务器B都是单点故障,数据库A与数据库B也都是单点故障.从而这些服务器所在的站点也是单点故障.这样,只要其中一个单点发生故障,整个数据库将不可用.一个&#8221;普通的&#8221;RAC就是为了解决其中的服务器单点故障的,如下图所示:<br />
<img src="http://lh4.ggpht.com/_Tj8VUwhrzbg/S6MoczU9CqI/AAAAAAAAAJQ/2jsB5-Bv4_8/rac.gif"/><br />
如果两个服务器的其中一个发生故障,数据库C将仍然可用.当然,使用RAC并不仅仅是为了实现HA.在使用RAC的其它的理由中,一个比较可靠的理由是为了实现伸缩性(Scalability):如果应用需求在将来出现增长,我们可以通过添加新的节点(Node)到集群中来解决.另外,通过使用RAC我们还可以选择使用服务管理(Service-Management)与负载均衡(Load Balance).简言之,RAC不仅仅是HA,在此详述其它原因已经超出本文的范畴了.从HA的视角看,使用RAC的缺陷是:数据库C以及相应的站点C是单点.如果站点C发生故障(比如火灾),数据库C将不可用.因此,将数据库伸展到两个站点就成为我们的选择了,这也是通常所说的扩展RAC.<br />
<img src="http://lh6.ggpht.com/_Tj8VUwhrzbg/S6Moc1lfpVI/AAAAAAAAAJM/zfgHb_jsZfg/extendedrac.gif"/><br />
现在,这两个站点就不再是单点了.数据库D是在两个站点之间做镜像的.这个架构的缺陷是两个站点之间的网络连接的成本,如果两个站点之间的距离比较远的话.这很关键,因为需要镜像的数据量会非常大.实际上,这使得两个站点之间的距离局限于几公里以内,而这与想要实现的灾难保护目标之间有冲突.这时,Dataguard就隆重登场了:利用DataGuard,我们很容易就可以实现长距离的灾难保护,因为,此时我们不再需要传输所有的数据量,而仅仅需要传输(相对小)的重做日志.在下图中,每个服务器都像上面的服务器A与服务器B一样,只有一个实例:<br />
<img src="http://lh6.ggpht.com/_Tj8VUwhrzbg/S6Mochb8b4I/AAAAAAAAAJI/P8Uc-jrNfRg/dataguard1.gif"/><br />
备用数据库由来自主数据库的重做日志. 当主库发生故障时,我们可以失败切换(Failover)到备库上并继续有效工作.这个失败切换工作可以由一个Observer(观察员程序,通常称为快速启动失败切换,Fast-Start Failover)自动实现.两个站点之间的距离达到几千公里(依赖于重做日志的传输策略与保护级别(protection level)).如果我们将RAC与Dataguard集合起来,我们就实现了MAA.显然,MAA是一个昂贵的解决方案,不过它也同时享有RAC与Dataguard的所有好处.<br />
远程镜像是一个广受欢迎的第三方HA解决方案.总体上,它的架构与下图类似:<br />
<img src="http://lh6.ggpht.com/_Tj8VUwhrzbg/S6ModRrxi7I/AAAAAAAAAJY/RGdK6iFBT5s/remotemirroring.gif"/><br />
这时,也没有哪个站点是单点的,类似于使用扩展RAC架构.这个解决方案的缺陷是:站点间的距离也是严格受限制的,理由与扩展RAC架构类似.同时,在镜像进行的时候,第二个站点是无法提供服务的,这一点与上述的Oracle提供的HA解决方案不同.使用RAC时,所有的服务器与相应的站点都可以提供服务.哪怕是使用Dataguard,备用数据库也不仅仅是等待主库发生故障.除此之外,它还可以提供只读访问服务,这将可以有效降低主库的负载.<br />
<img src="http://lh5.ggpht.com/_Tj8VUwhrzbg/S6ModAA9GII/AAAAAAAAAJU/uGYJm45tRyc/realtimequery.gif"/><br />
上图展示了Oracle 11g的新特性&#8221;物理备用数据库上的实时查询&#8221;.在恢复过程中时,备用数据库也在同时提供只读访问.另外,还可以在物理备库(Physical Standby)上做离线备份(OffLoad Backup).</p>
<p>附注:<br />
其实还有另外一种可选择的架构. 基于Data Guard与单实例的一个结合.<br />
类似于上面介绍的远程Data Guard方案, 做了一点修正: 将当前主库的一组Redo 日志放到远程(当然也受限于距离所产生的San 访问延时).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.alidba.net/index.php/archives/406/feed</wfw:commentRss>
		</item>
		<item>
		<title>使用数据库存图片</title>
		<link>http://www.alidba.net/index.php/archives/400</link>
		<comments>http://www.alidba.net/index.php/archives/400#comments</comments>
		<pubDate>Thu, 11 Mar 2010 15:55:43 +0000</pubDate>
		<dc:creator>八神</dc:creator>
		
		<category><![CDATA[大话技术]]></category>

		<category><![CDATA[图片]]></category>

		<guid isPermaLink="false">http://www.alidba.net/?p=400</guid>
		<description><![CDATA[图片是网站上很重要的资源，用户发布的产品图片，用户的logo，AV男，兽兽女，犀利哥等等等等，一个稍具规模的网站，图片的数量可能是千万级，这种资源的特点就是文件小，数量大，每个文件在几字节到几K不等，所以针对图片的访问，基本是非常离散的IO，考验的是系统的磁盘并发和CPU处理能力
一般网站，图片都是存放专门的图片服务器，可集中也可以分布式，比如有条件的可以购买昂贵的NAS存储，由主机拖着，以NFS或者HTTP的方式，供前面的应用访问，或者使用多台廉价PC，图片分布打散到每个机器，前台应用解决图片存取和访问策略，以便充分利用所有资源，在应用与图片服务器中间还可能加一层cache，来缓冲前台的访问压力
上面所说的方法，弊端是有很多的
1.文件系统一定是要使用的，为了管理数千万的图片，必须进行目录分层，因为一个目录下不可能存放太多的文件，前期的目录规划要考虑后期的扩展，还有图片分布均匀，这样做下来，往往目录的深度会达到5层甚至7层
2.数据迁移，备份怎么做？高级的NAS存储，有自己的卷复制，但这个粒度太粗，如果要细分到底层或中间层，会有点力不从心，对于这种大数据量的小文件拷贝，PC也是非常吃力
3.每一个图片的访问，基本会做5-7次的目录跳转，转换到磁盘，也可能有10次物理IO了，在并发量上来的时候，磁盘会是个瓶颈，当然，分布式是个方向
这里想到了另外一种方法，利用数据库来存放图片，存储的方式就是现在最流行的key-value
create table mypic
(
key number not null,
pic blob
);
create index ind_picid on mypic(key);
key是图片名称，事先最好统一规划一下，使用number数字来命名，并针对key建立索引
VALUE就是图片内容，用blob来保存
访问一个图片的方式就是：
获取图片名称  数据key
走key上的索引，定位到记录表记录
根据表记录，定位到图片的blob，并读取
这个方法的优点：
1.单个图片的访问路径缩短，数字索引比较小，分区做的好的话可能小到两层，从索引到表，到blob段，大概是4-5跳
并且KEY是区分度非常高的数据类型，在索引每层的横向检索中，不会超过1个数据块，而文件目录结构中，子目录繁多，
要遍历这层的inode后，才知道具体跳转的下层位置
2.备份方式比较灵活，可以基于整个数据库，或者单独的表，数据的迁移，删除，都是基于表级别的，比较直观，方便
3.可以在数据库层面，考虑图片的水平拆分，垂直拆分，分表，分库，都不错
4.数据库的复制技术可以派上用场，读写分离
这里数据库完全是当成一个KEY-VALUE的存储在用，我们可以考虑将一些廉价的PC堆在一起，做成一个picdb的群集，
大致画了一个草图，当然在WEB与picdb间应该还有层cache的,这个方法是YY出来的，可能很多地方不成熟，但SY强身，YY强国，没有想法，哪来的动力？欢迎各位专业人士拍砖

]]></description>
			<content:encoded><![CDATA[<p>图片是网站上很重要的资源，用户发布的产品图片，用户的logo，AV男，兽兽女，犀利哥等等等等，一个稍具规模的网站，图片的数量可能是千万级，这种资源的特点就是文件小，数量大，每个文件在几字节到几K不等，所以针对图片的访问，基本是非常离散的IO，考验的是系统的磁盘并发和CPU处理能力</p>
<p>一般网站，图片都是存放专门的图片服务器，可集中也可以分布式，比如有条件的可以购买昂贵的NAS存储，由主机拖着，以NFS或者HTTP的方式，供前面的应用访问，或者使用多台廉价PC，图片分布打散到每个机器，前台应用解决图片存取和访问策略，以便充分利用所有资源，在应用与图片服务器中间还可能加一层cache，来缓冲前台的访问压力</p>
<p>上面所说的方法，弊端是有很多的<br />
1.文件系统一定是要使用的，为了管理数千万的图片，必须进行目录分层，因为一个目录下不可能存放太多的文件，前期的目录规划要考虑后期的扩展，还有图片分布均匀，这样做下来，往往目录的深度会达到5层甚至7层<br />
2.数据迁移，备份怎么做？高级的NAS存储，有自己的卷复制，但这个粒度太粗，如果要细分到底层或中间层，会有点力不从心，对于这种大数据量的小文件拷贝，PC也是非常吃力<br />
3.每一个图片的访问，基本会做5-7次的目录跳转，转换到磁盘，也可能有10次物理IO了，在并发量上来的时候，磁盘会是个瓶颈，当然，分布式是个方向</p>
<p>这里想到了另外一种方法，利用数据库来存放图片，存储的方式就是现在最流行的key-value</p>
<p>create table mypic<br />
(<br />
key number not null,<br />
pic blob<br />
);</p>
<p>create index ind_picid on mypic(key);</p>
<p>key是图片名称，事先最好统一规划一下，使用number数字来命名，并针对key建立索引<br />
VALUE就是图片内容，用blob来保存<br />
访问一个图片的方式就是：<br />
获取图片名称  数据key<br />
走key上的索引，定位到记录表记录<br />
根据表记录，定位到图片的blob，并读取</p>
<p>这个方法的优点：<br />
1.单个图片的访问路径缩短，数字索引比较小，分区做的好的话可能小到两层，从索引到表，到blob段，大概是4-5跳<br />
并且KEY是区分度非常高的数据类型，在索引每层的横向检索中，不会超过1个数据块，而文件目录结构中，子目录繁多，<br />
要遍历这层的inode后，才知道具体跳转的下层位置<br />
2.备份方式比较灵活，可以基于整个数据库，或者单独的表，数据的迁移，删除，都是基于表级别的，比较直观，方便<br />
3.可以在数据库层面，考虑图片的水平拆分，垂直拆分，分表，分库，都不错<br />
4.数据库的复制技术可以派上用场，读写分离</p>
<p>这里数据库完全是当成一个KEY-VALUE的存储在用，我们可以考虑将一些廉价的PC堆在一起，做成一个picdb的群集，<br />
大致画了一个草图，当然在WEB与picdb间应该还有层cache的,这个方法是YY出来的，可能很多地方不成熟，但SY强身，YY强国，没有想法，哪来的动力？欢迎各位专业人士拍砖</p>
<p><img class="alignnone size-full wp-image-404" src="http://www.alidba.net/wp-content/uploads/2010/03/ppp1.jpg" alt="ppp1" width="748" height="653" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.alidba.net/index.php/archives/400/feed</wfw:commentRss>
		</item>
		<item>
		<title>不平衡的索引?</title>
		<link>http://www.alidba.net/index.php/archives/394</link>
		<comments>http://www.alidba.net/index.php/archives/394#comments</comments>
		<pubDate>Tue, 02 Mar 2010 06:49:12 +0000</pubDate>
		<dc:creator>jametong</dc:creator>
		
		<category><![CDATA[大话技术]]></category>

		<category><![CDATA[b-tree]]></category>

		<category><![CDATA[balanced tree index]]></category>

		<category><![CDATA[index block split]]></category>

		<category><![CDATA[index split]]></category>

		<category><![CDATA[jonathan lewis]]></category>

		<category><![CDATA[treedump]]></category>

		<guid isPermaLink="false">http://www.alidba.net/?p=394</guid>
		<description><![CDATA[本文翻译自Jonathan Lewis早年写在dbazine上的文章unbalanced indexes? 本文的word版本可以到此处下载
原文参见: 不平衡的索引?
不平衡的索引?
by Jonathan Lewis
网络上有多篇介绍Oracle索引实现机制的文章,都提及需要经常重建索引.在这些文章中的某处,总是会出现这样一段简短的描述,索引会如何变的不平衡,以及可能导致的后果.很不幸,它们好像忽视了这样一个事实,Oracle使用的B-tree机制是一种&#8221;平衡B-tree&#8221;索引,也就是说,索引无法变得不平衡.
&#8220;平衡&#8221;到底意味着什么?
既然Oracle的索引使用的是平衡B-tree,为什么还有如此多的人相信他们的索引会变得不平衡呢?
另外,平衡B-tree到底又是什么呢?
第二个问题的答案可能能够帮助我们得到第一个问题的答案.
从技术角度讲,平衡B-tree的显要特性是,在任意时间点,任何叶子节点(leaf block)到根节点(root block)的距离都相等,平衡是指从顶部到底部的平衡.
就Oracle来说,执行一个treedump命令就可以很容易发现这一点,如图-1所示:
select	object_id
from	user_objects
where	object_type = 'INDEX'
and	object_name = 'T1_IDX1'
-- and 	subobject_name = . . .
;
alter session set events '
'immediate trace name treedump level N';
图-1: 一次索引树转储涉及到的步骤
首先,需要找到你想要转储(dump)索引或者索引分区(index partition)的object_id;接着,将object_id作为level的参数来调用treedump事件. 如果检查这个索引树(tree dump)转储生成的跟踪文件,你将发现类似于图-2中所示的结果.
branch: 0x14001aa 20971946 (.. level 2)
  branch: 0x14003ef 20972527 (.. level 1)
    leaf: 0x14001ab 20971947 (..)
    leaf: [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>本文翻译自<a href="http://jonathanlewis.wordpress.com/">Jonathan Lewis</a>早年写在dbazine上的文章<a href="http://www.dbazine.com/oracle/or-articles/jlewis13">unbalanced indexes?</a> 本文的word版本可以到<a href="http://www.jlcomp.demon.co.uk/13_unbalanced_indexes.doc">此处下载</a></p>
<p>原文参见: <a href="http://www.dbthink.com/?p=193">不平衡的索引?</a></p></blockquote>
<p><strong>不平衡的索引?</strong><br />
<em>by Jonathan Lewis</em></p>
<p>网络上有多篇介绍Oracle索引实现机制的文章,都提及需要经常重建索引.在这些文章中的某处,总是会出现这样一段简短的描述,索引会如何变的不平衡,以及可能导致的后果.很不幸,它们好像忽视了这样一个事实,Oracle使用的B-tree机制是一种&#8221;平衡B-tree&#8221;索引,也就是说,索引无法变得不平衡.</p>
<p><strong>&#8220;平衡&#8221;到底意味着什么?</strong></p>
<p>既然Oracle的索引使用的是平衡B-tree,为什么还有如此多的人相信他们的索引会变得不平衡呢?<br />
另外,平衡B-tree到底又是什么呢?<br />
第二个问题的答案可能能够帮助我们得到第一个问题的答案.<br />
从技术角度讲,平衡B-tree的显要特性是,在任意时间点,任何叶子节点(leaf block)到根节点(root block)的距离都相等,平衡是指从顶部到底部的平衡.<br />
就Oracle来说,执行一个treedump命令就可以很容易发现这一点,如图-1所示:</p>
<pre>select	object_id
from	user_objects
where	object_type = 'INDEX'
and	object_name = 'T1_IDX1'
-- and 	subobject_name = . . .
;
alter session set events '
'immediate trace name treedump level N';</pre>
<p><em>图-1: 一次索引树转储涉及到的步骤</em></p>
<p>首先,需要找到你想要转储(dump)索引或者索引分区(index partition)的object_id;接着,将object_id作为level的参数来调用treedump事件. 如果检查这个索引树(tree dump)转储生成的跟踪文件,你将发现类似于图-2中所示的结果.</p>
<pre>branch: 0x14001aa 20971946 (.. level 2)
  branch: 0x14003ef 20972527 (.. level 1)
    leaf: 0x14001ab 20971947 (..)
    leaf: 0x14001ac 20971948 (..)</pre>
<p><em>图-2: 从索引树转储结果中提取出的一段内容</em></p>
<p>这个跟踪文件以递归降序的方式展示索引的分支块(branch block,根块只是分支块的一个特例)与叶子块.注意,转储内容的第一个块(根块)记录了一个高度(level),并且它下面的每一个分支块也都记录了一个高度,但是叶子块没有记录高度.<br />
根块的高度就是索引的blevel(执行analyze index命令之后会记录在视图dba_indexes中).索引的高度(height,执行命令validate index后会记录在视图index_stats中)就是blevel + 1.<br />
每一个叶子块到根块的距离就正好有这么多步.索引总是平衡的.<br />
那么为什么有那么多人相信Oracle会允许索引变得不平衡呢?</p>
<p><strong>我应负的责任</strong></p>
<p>此时,我必须承认我有罪,仅仅在一年前(2002年5月),我也重复了一个关于块分裂(index block split)的众所周知但是却完全错误的描述.虽然我知悉(在我的书(2000年12月,Practical Oracle 8i)中对此做了说明) treedump的细节,但我还是这样做了.<br />
我猜想,这种错误的观念最初产生于Oracle5(很多年以前)手册的说明,其大意是,因为&#8221;没有一个叶子块到根块的距离比任何其他叶子块到根块的距离远.&#8221;, 所以Oracle索引是平衡的.将这个表述与一个过于简化的块分裂的图结合到一起,瞧,一个几乎牢不可破的神话就诞生了.<br />
图-3和图-4描绘了一个非常常见,但是完全错误的关于叶子块如何分裂的概念.<br />
<img src="http://lh4.ggpht.com/_Tj8VUwhrzbg/S4yrRrGhyaI/AAAAAAAAAII/Z2Q3VZtInnY/jlewis13-1.gif"/><br />
<em>图-3: 叶子块将要分裂前的索引结构</em><br />
<img src="http://lh4.ggpht.com/_Tj8VUwhrzbg/S4yrRvhpPaI/AAAAAAAAAIM/4ZdSMJN-_pQ/jlewis13-2.gif"/><br />
<em>图-4 这不是叶子块分裂发生的方式</em><br />
有这样一个流传广泛的说法,叶子块分裂到两个全新的块,这两个块分享它的所有数据;接着, Oracle在原来的叶子块的位置插入一个新的分支块来持有指向这两个块的指针.因此,在这样一个错误的视角下,这个索引的右边就会比左边更深.(经常会有人说,创建在基于序列的字段上的索引会带来最大的问题,因为,从这个理论来推导,最右边的叶子块到根块的距离会越来越远,没分裂一次,就会降低一层.)<br />
事实上,这个工作Oracle做得更加精致前瞻并有效得多. 图-5所示是一个复杂的叶子块分裂的结果.<br />
<img src="http://lh4.ggpht.com/_Tj8VUwhrzbg/S4yrRuRproI/AAAAAAAAAIQ/nFcWkGa-qJg/jlewis13-3.gif"/><br />
<em>图-5: 一次递归分裂后的索引结构图</em><br />
由于这个叶子块分裂成了两个块,Oracle会尝试往当前指向这个叶子块的分支块中插入一个额外的指针.<br />
但是,如果这个分支块也满了,Oracle会继续将这个分支块也分裂成两个块,并且在两个分支块之间分配现存块里的指向叶子块的指针,并且(递归地) 在这个分支块的上一级的分支块中插入一个指向这个新的分支块的新的分支指针.<br />
如果在这个过程中,Oracle抵达了根块,然而这个根块也满了,那么根块也必须分裂.在这种情况下,Oracle将创建一个新的根块来持有这两个分支指针.(事实上,Oracle处理根块分裂的方式与处理普通的分支块的分裂有一点细微的差异,以确保无论根块上发生了多少次的分裂,总是可以在物理段的同一个位置找到根块.)<br />
注意,这个递归的分裂操作这样沿着索引树不断攀升意味着,无论何时,索引总能保持平衡.</p>
<p><strong>为什么这个神话如此牢固?</strong></p>
<p>为什么这个关于不平衡的索引的神话能够长盛不衰,是否存在一些原因呢?我这答案是确实存在一些原因.<br />
要切记,当我们讨论B-tree的时候,单词&#8221;balanced&#8221;的定义有非常严格的含义.然而,这个单词还有一种完全不同的解释.<br />
例如,你将如何描述图-6中的这个索引,其中根块指向六个叶子块,但是其中一个叶子块是空的,有三个块几乎是空的,还有两个块塞的很满.(注意,从根块到叶子块的这些额外的说明是为了强调索引填充分布的多么不均匀;实际上,根块到每个叶子块都只有一个指针.)<br />
<img src="http://lh4.ggpht.com/_Tj8VUwhrzbg/S4yrRqip67I/AAAAAAAAAIU/Ihz54GfR97Q/jlewis13-4.gif"/><br />
<em>图-6 &#8220;不平衡&#8221;的一种非技术理解</em></p>
<p>看到这种图案的索引,一个&#8221;人&#8221;的真实反应都会人为它&#8221;不平衡&#8221;.很明显,索引的右手边要比左手边&#8221;重&#8221;.很不幸,当技术表达意味着完全不同的东西的时候,这种非正式的人为表达应该更加恰当.<br />
或许正是这种技术表达与非正式的人为表达之间的冲突导致了这种混淆.<br />
在这种非正式的意义上,在基于序列值的字段上索引很容易就会变得&#8221;不平衡&#8221;,特别是它们被用来表征/处理先进先出(FIFO)队列机制的时候.然而,即使它们(在非正式语境中)是不平衡的,它们(在技术上)仍然是平衡的B-tree.<br />
(推动使用类似于&#8221;扭曲&#8221;或者&#8221;分布不均匀&#8221;作为术语来描述这种类型的索引,或许会是个好主意.)<br />
有时,仅仅几篇草率地使用术语的文章或报告就可能构建一个神话,在这个例子中,就是一个导致众多DBA浪费无数小时的时间去做不必要的索引重建的神话.<br />
记住,你下一次认为Oracle表现愚蠢或者低效的时候,很可能问题是出在一个古老的误解上面,而不是Oracle软件本身的问题.</p>
<p><strong>告警提醒</strong></p>
<p>如果你还想进一步地研究,treedump选项还有一系列的问题需要注意.对于大部分的Oracle版本,它看似对索引段中的每个块都生成一行输出,这样可能会非常昂贵并且速度缓慢,因为它需要按顺序访问索引中的每一个数据块.然而,在Oracle 9.0中,跟踪文件看似会对每一个块做一个整块转储,这样会使得转储文件非常巨大,转储速度也会非常缓慢.<br />
第二个问题是所有版本都一致的.如果这个索引是在定义主键约束或者唯一键约束时生成的,Oracle就会设置ind$表的flags字段的第13位,而这将导致treedump程序崩溃并报出错误&#8221;invalid value.&#8221;分区索引的分区段不会产生这个问题,但是对于所有其他类型的主键索引与唯一索引(包含非分区索引组织表,IOT),这都很恼人.先创建索引,再基于这个索引创建约束通常是个好主意, 这样处理可以避免除索引组织表外的其他所有条件下的问题. 在紧急情况下,你可以修改ind$表来清除这一位,但是很明显,需要先取得Oracle支持的认可.</p>
<p><strong>结论</strong></p>
<p>当谈到平衡B-tree索引的时候,术语&#8221;平衡&#8221;指的是从顶部到底部,而不是从左到右.<br />
Oracle确实实现了一个版本的&#8221;平衡B-tree索引&#8221;,因此在任何时候,索引中的所有叶子块到根块的距离都是完全相同的,如果最近对这个索引作过分析的话,可以从视图user_indexes的字段blevel找到它,如果刚刚对这个索引执行过validate index的话,可以从视图index_stats的height字段(等价于blevel+1)得到.<br />
当听到你应该经常重建索引,因为&#8221;这些索引已经变得不平衡&#8221;时,要抵制这种理由.因为它不是一个靠得住的理由.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.alidba.net/index.php/archives/394/feed</wfw:commentRss>
		</item>
	</channel>
</rss>
