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

<channel>
	<title>WR blog</title>
	<atom:link href="http://www.csus4.net/d/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.csus4.net/d</link>
	<description>about Enterprise IT, Oracle Database, Jazz/Fusion Music, etc...</description>
	<pubDate>Thu, 12 Apr 2012 04:05:26 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.2</generator>
	<language>en</language>
			<item>
		<title>おかげさまでUnconferenceは大盛況でした！</title>
		<link>http://www.csus4.net/d/2012/04/08/jpoug_unconference/</link>
		<comments>http://www.csus4.net/d/2012/04/08/jpoug_unconference/#comments</comments>
		<pubDate>Sun, 08 Apr 2012 12:58:37 +0000</pubDate>
		<dc:creator>wr</dc:creator>
		
		<category><![CDATA[Oracle]]></category>

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

		<guid isPermaLink="false">http://www.csus4.net/d/?p=669</guid>
		<description><![CDATA[JPOUGがお送りした最初のイベント、Oracle OpenWorld Unconference presented by JPOUG は、おかげさまで大盛況で終了しました！ ご参加していただいた皆様、貴重なお時間を割いていただき、どうもありがとうございました！

私は、「バッチ処理にバインド変数はもうやめません？ ~バッチ処理の突発遅延を題材にして考えてみる~」と題して、バッチ処理における突発的な処理遅延についてお話させていただきました。 


少しセッション時間が短かったこともあり、駆け足での一方的な説明になってしまい、Unconferenceというよりは通常のセミナーになってしまったな・・・ と思っていたところ、セッションの最後の質問タイムで、聴講いただいた方と意見の交換をすることができ、Unconference的なエッセンスを入れ込むことができたように思っています（結果オーライw）。 Nさん、ご質問いただきありがとうございました！（感謝感激）

また、幸運なことに、本セッションの前に、SQLのバインド変数化という題材をOLTPの観点で、sh2さんにご説明いただいていました。本セッションではOLTPではなくバッチの観点で説明しましたので、同じ題材をそれぞれのセッションで異なる観点で説明で来た形になり、聞いていただいた方がより理解を深めることができたのではと考えています。sh2さん、ありがとうございました！

 Oracle Database経験者がMySQLの設計思想を知っていろいろ考える会

当日発表に使用した資料を以下においておきます。





さて、ご参加いただいた方は実感されたとは思いますが、日本オラクルさま主催のセッションとはかなり色合いの異なる内容になっています。(マニュアル活用方法を題材にしたエンジニアのスキル向上に関するアドバイスしかり、MySQLとOracle Databaseの比較しかり・・・） 私個人の意見ですが、この点が 日本オラクルさまでなく、JPOUG がイベントを企画する大きな意味であると思っています。
今回のイベントの雰囲気を伝えるtweetは、Oracle OpenWorld Unconference presented by JPOUG - Togetter にまとまっています。（楽しそうでしょ？）
6月を目標に次回イベントを企画中です。企画が進行しだいイベント情報を発信させていただきますので、
ぜひFacebookページに「いいね！」してみてください！

Facebook - JPOUG fanpage

ご支援いただいた皆様に感謝したいと思います。

Oracle OpenWorld Tokyo 2012事務局のみなさま、OTN事務局のみなさま、Unconferenceをご支援いただきありがとうございました。まだ立ち上がったばかりの団体に対して、貴重な場を提供いただき、まことにありがとうございました。

セッションをご担当いただいたスピーカのみなさま、ありがとうございました。業務などで多忙な状況で、準備や調整を実施いただいたかと思います。みなさまのおかげで、イベント全体のセッション内容を、バリエーションに富んだ、より価値あるものにできました。まことにありがとうございます。

最後に、私のこのような活動に理解を示してくれている、職場のみなさん、ありがとうございます！
私が心置きなくセッションを担当できたのも、みなさんのおかげです！ 感謝してもしきれません、ありがとう！！！
]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.jpoug.org">JPOUG</a>がお送りした最初のイベント、Oracle OpenWorld Unconference presented by JPOUG は、おかげさまで大盛況で終了しました！ ご参加していただいた皆様、貴重なお時間を割いていただき、どうもありがとうございました！</p>

<p>私は、「バッチ処理にバインド変数はもうやめません？ ~バッチ処理の突発遅延を題材にして考えてみる~」と題して、バッチ処理における突発的な処理遅延についてお話させていただきました。 
<a href="http://www.csus4.net/d/wp-content/uploads/unconf.jpg"><img src="http://www.csus4.net/d/wp-content/uploads/unconf.jpg" alt="" title="unconference" width="600" height="358" class="alignnone size-medium wp-image-670" /></a></p>

<p>少しセッション時間が短かったこともあり、駆け足での一方的な説明になってしまい、Unconferenceというよりは通常のセミナーになってしまったな・・・ と思っていたところ、セッションの最後の質問タイムで、聴講いただいた方と意見の交換をすることができ、Unconference的なエッセンスを入れ込むことができたように思っています（結果オーライw）。 Nさん、ご質問いただきありがとうございました！（感謝感激）</p>

<p>また、幸運なことに、本セッションの前に、SQLのバインド変数化という題材をOLTPの観点で、<a href="http://d.hatena.ne.jp/sh2/">sh2さん</a>にご説明いただいていました。本セッションではOLTPではなくバッチの観点で説明しましたので、同じ題材をそれぞれのセッションで異なる観点で説明で来た形になり、聞いていただいた方がより理解を深めることができたのではと考えています。sh2さん、ありがとうございました！</p>

<ul><li><a href="http://d.hatena.ne.jp/sh2/20120404"> Oracle Database経験者がMySQLの設計思想を知っていろいろ考える会</a></li></ul>

<p>当日発表に使用した資料を以下においておきます。</p>

<p><a href="http://www.csus4.net/d/wp-content/uploads/120406_BindVariablesOnBatch.pdf">
<img src="http://www.csus4.net/d/wp-content/uploads/20120406_unconf_slide1.jpg" width="639" height="479" class="alignnone size-medium wp-image-670" />
</a></p>

<p>さて、ご参加いただいた方は実感されたとは思いますが、日本オラクルさま主催のセッションとはかなり色合いの異なる内容になっています。(マニュアル活用方法を題材にしたエンジニアのスキル向上に関するアドバイスしかり、MySQLとOracle Databaseの比較しかり・・・） 私個人の意見ですが、この点が 日本オラクルさまでなく、JPOUG がイベントを企画する大きな意味であると思っています。
今回のイベントの雰囲気を伝えるtweetは、<a href="http://togetter.com/li/284927">Oracle OpenWorld Unconference presented by JPOUG - Togetter</a> にまとまっています。（楽しそうでしょ？）
6月を目標に次回イベントを企画中です。企画が進行しだいイベント情報を発信させていただきますので、
ぜひFacebookページに「いいね！」してみてください！</p>

<ul><li><a href="http://www.facebook.com/jpougfan">Facebook - JPOUG fanpage</a></li></ul>

<p>ご支援いただいた皆様に感謝したいと思います。</p>

<p>Oracle OpenWorld Tokyo 2012事務局のみなさま、OTN事務局のみなさま、Unconferenceをご支援いただきありがとうございました。まだ立ち上がったばかりの団体に対して、貴重な場を提供いただき、まことにありがとうございました。</p>

<p>セッションをご担当いただいたスピーカのみなさま、ありがとうございました。業務などで多忙な状況で、準備や調整を実施いただいたかと思います。みなさまのおかげで、イベント全体のセッション内容を、バリエーションに富んだ、より価値あるものにできました。まことにありがとうございます。</p>

<p>最後に、私のこのような活動に理解を示してくれている、職場のみなさん、ありがとうございます！
私が心置きなくセッションを担当できたのも、みなさんのおかげです！ 感謝してもしきれません、ありがとう！！！</p>
]]></content:encoded>
			<wfw:commentRss>http://www.csus4.net/d/2012/04/08/jpoug_unconference/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Oracle OpenWorld Unconference presented by JPOUG</title>
		<link>http://www.csus4.net/d/2012/03/02/oracle-openworld-unconference-presented-by-jpoug/</link>
		<comments>http://www.csus4.net/d/2012/03/02/oracle-openworld-unconference-presented-by-jpoug/#comments</comments>
		<pubDate>Fri, 02 Mar 2012 03:50:32 +0000</pubDate>
		<dc:creator>wr</dc:creator>
		
		<category><![CDATA[Oracle]]></category>

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

		<guid isPermaLink="false">http://www.csus4.net/d/?p=663</guid>
		<description><![CDATA[JPOUGがお送りする最初のイベントは、Oracle OpenWorld Unconference !!
Oracle OpenWorld Tokyo 2012の最終日(4/6(金))に
12:30から18:00ごろまで開催します！





Unconference とは、少なめの人数でスピーカーとリスナーがいろいろやり合いながらすすめる
ユニークな形式のセミナー(?)です。
oracletech.jpにも紹介記事があります。こちらを見ていただくと、よりイメージをつかめるかも・・・


Oracle OpenWorld の特別セッション「Oracle OpenWorld Unconference presented by JPOUG」


場所は 六本木アカデミーヒルズ49 です。以下のURLの地図も合わせてご覧ください！

http://www.oracle.com/openworld/jp-ja/access/index.html

http://www.academyhills.com/forum/room/49/index.html

開催時間帯は、JPUOGメンバーが
誰かしら会場にいるはずです。Oracle製品に携わるエンジニアのお祭りです。楽しみましょう！

なにかご要望やご意見がある方は、Facebookページにコメントを。

Facebook - JPOUG fanpage

ついでに「いいね！」してもらえるとうれしいです。
]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.jpoug.org">JPOUG</a>がお送りする最初のイベントは、Oracle OpenWorld Unconference !!
<a href="http://www.oracle.com/openworld/jp-ja/index.html">Oracle OpenWorld Tokyo 2012</a>の最終日(4/6(金))に
12:30から18:00ごろまで開催します！</p>

<p><a href="http://oracletech.jp/seminar/recommended/000521.html">
<img src="http://www.csus4.net/d/wp-content/uploads/jpoug_unconference.png" alt="" title="Oracle OpenWorld Unconference presented by JPOUG" />
</a></p>

<p>Unconference とは、少なめの人数でスピーカーとリスナーがいろいろやり合いながらすすめる
ユニークな形式のセミナー(?)です。
oracletech.jpにも紹介記事があります。こちらを見ていただくと、よりイメージをつかめるかも・・・</p>

<p><a href="http://oracletech.jp/seminar/recommended/000521.html">
Oracle OpenWorld の特別セッション「Oracle OpenWorld Unconference presented by JPOUG」
</a></p>

<p>場所は 六本木アカデミーヒルズ49 です。以下のURLの地図も合わせてご覧ください！</p>

<p><a href="http://www.oracle.com/openworld/jp-ja/access/index.html">http://www.oracle.com/openworld/jp-ja/access/index.html</a></p>

<p><a href="http://www.academyhills.com/forum/room/49/index.html">http://www.academyhills.com/forum/room/49/index.html</a></p>

<p>開催時間帯は、<a href="http://www.jpoug.org/%E8%AA%AC%E6%98%8E">JPUOGメンバー</a>が
誰かしら会場にいるはずです。Oracle製品に携わるエンジニアのお祭りです。楽しみましょう！</p>

<p>なにかご要望やご意見がある方は、Facebookページにコメントを。</p>

<p><a href="http://www.facebook.com/jpougfan">Facebook - JPOUG fanpage</a></p>

<p>ついでに「いいね！」してもらえるとうれしいです。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.csus4.net/d/2012/03/02/oracle-openworld-unconference-presented-by-jpoug/feed/</wfw:commentRss>
		</item>
		<item>
		<title>JPOUG Webサイト &#038; Facebookページ公開！ + IOUCに参加</title>
		<link>http://www.csus4.net/d/2012/03/02/jpoug-coming/</link>
		<comments>http://www.csus4.net/d/2012/03/02/jpoug-coming/#comments</comments>
		<pubDate>Thu, 01 Mar 2012 23:00:09 +0000</pubDate>
		<dc:creator>wr</dc:creator>
		
		<category><![CDATA[Oracle]]></category>

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

		<guid isPermaLink="false">http://www.csus4.net/d/?p=655</guid>
		<description><![CDATA[またまた久しぶりなBlogの更新となっております・・・

去年から運営メンバーの一員として打ち合わせなどに参加してきましたが、
JPOUG (Japan Oracle User Group)のWebサイトを立ち上げることができました。



JPOUG (Japan Oracle User Group) - http://www.jpoug.org 

あわせて、各種の交流やイベント告知などの情報発信のため、Facebookページも作成しています。
もしよろしければ、アクセスいただき、「いいね！」をお願いいたします。

Facebook - JPOUG fanpage

また、JPOUGがIOUC(International Oracle Users Group Community)へ参加することに決まりました。

http://www.iouc.org/p/cm/ld/fid=45&#38;region=14&#38;gid=590

Oracle製品ユーザーの交流を深めましょう！！
]]></description>
			<content:encoded><![CDATA[<p>またまた久しぶりなBlogの更新となっております・・・</p>

<p>去年から運営メンバーの一員として打ち合わせなどに参加してきましたが、
JPOUG (Japan Oracle User Group)のWebサイトを立ち上げることができました。</p>

<p><a href="http://www.jpoug.org"><img src="http://www.csus4.net/d/wp-content/uploads/jpouglogo.png" alt="" title="jpouglogo" /></a></p>

<p><a href="http://www.jpoug.org">JPOUG (Japan Oracle User Group) - http://www.jpoug.org </a></p>

<p>あわせて、各種の交流やイベント告知などの情報発信のため、Facebookページも作成しています。
もしよろしければ、アクセスいただき、「いいね！」をお願いいたします。</p>

<p><a href="http://www.facebook.com/jpougfan">Facebook - JPOUG fanpage</a></p>

<p>また、JPOUGがIOUC(International Oracle Users Group Community)へ参加することに決まりました。</p>

<p><a href="http://www.iouc.org/p/cm/ld/fid=45&#038;region=14&#038;gid=590">http://www.iouc.org/p/cm/ld/fid=45&amp;region=14&amp;gid=590</a></p>

<p>Oracle製品ユーザーの交流を深めましょう！！</p>
]]></content:encoded>
			<wfw:commentRss>http://www.csus4.net/d/2012/03/02/jpoug-coming/feed/</wfw:commentRss>
		</item>
		<item>
		<title>9/30(金) Oracle LOVERS2 でお話させていただきました。</title>
		<link>http://www.csus4.net/d/2011/10/14/oraclelovers2/</link>
		<comments>http://www.csus4.net/d/2011/10/14/oraclelovers2/#comments</comments>
		<pubDate>Fri, 14 Oct 2011 00:00:03 +0000</pubDate>
		<dc:creator>wr</dc:creator>
		
		<category><![CDATA[Oracle]]></category>

		<guid isPermaLink="false">http://www.csus4.net/d/?p=648</guid>
		<description><![CDATA[Blogの更新が滞り、申し訳ございません・・・
9/30(金) Oracle LOVERS  シーズン2 第2回 でお話させていただきました。

50名強(もしかするとそれ以上)という多くの方にご出席いただいただけでなく、
著名なOracleエンジニア方々の前で話すということで、非常に緊張いたしましたが
主催者の吉田さんのご配慮もあり、楽しい時間をすごすことができました。


Oracle LOVERS シーズン2 第2回 - oracletech.jp 
Oracle LOVERS シーズン2 第2回 - Zussar


わざわざ貴重なお時間を割いて、ご参加いただいた皆様、ありがとうございました。
実際の業務に有用な情報を1つでもご提供できたらうれしく思います。

また、主催者の吉田さん、いつもありがとうございます。
吉田さんの人柄がなせるものと思いますが、Oracle LOVERSはいつもリラックスした楽しい雰囲気で、
とてもすばらしいですね。
お忙しいとは思いますが、今後もぜひOracle LOVERSを継続していただけたらと思います。

今回の発表資料を公開する予定はありませんが、前半部分のデモで多用した
DBMS_XPLAN.DISPLAY_CURSORの使い方については過去のBlogエントリの内容が参考になると
思いますので、以下にリンクを張っておきます。参考にしていただければ幸いです。


SQLパフォーマンス問題調査でEXPLAIN PLAN、SQLトレースは（ほとんど）使わない
DBMS_XPLAN.DISPLAY_CURSORの使い方とちょっとした落とし穴
DISPLAY_CURSORでCBOの見積りミスを簡単に確認する


それでは・・・
]]></description>
			<content:encoded><![CDATA[<p>Blogの更新が滞り、申し訳ございません・・・
9/30(金) Oracle LOVERS  シーズン2 第2回 でお話させていただきました。</p>

<p>50名強(もしかするとそれ以上)という多くの方にご出席いただいただけでなく、
著名なOracleエンジニア方々の前で話すということで、非常に緊張いたしましたが
主催者の吉田さんのご配慮もあり、楽しい時間をすごすことができました。</p>

<ul>
<li><a href="http://oracletech.jp/seminar/recommended/000387.html">Oracle LOVERS シーズン2 第2回 - oracletech.jp</a> </li>
<li><a href="http://www.zusaar.com/event/agZ6dXNhYXJyDQsSBUV2ZW50GP_jBgw">Oracle LOVERS シーズン2 第2回 - Zussar</a></li>
</ul>

<p>わざわざ貴重なお時間を割いて、ご参加いただいた皆様、ありがとうございました。
実際の業務に有用な情報を1つでもご提供できたらうれしく思います。</p>

<p>また、主催者の吉田さん、いつもありがとうございます。
吉田さんの人柄がなせるものと思いますが、Oracle LOVERSはいつもリラックスした楽しい雰囲気で、
とてもすばらしいですね。
お忙しいとは思いますが、今後もぜひOracle LOVERSを継続していただけたらと思います。</p>

<p>今回の発表資料を公開する予定はありませんが、前半部分のデモで多用した
DBMS_XPLAN.DISPLAY_CURSORの使い方については過去のBlogエントリの内容が参考になると
思いますので、以下にリンクを張っておきます。参考にしていただければ幸いです。</p>

<ul>
<li><a href="http://www.csus4.net/d/2011/02/24/whynotuse_explainplan_sqltrace/">SQLパフォーマンス問題調査でEXPLAIN PLAN、SQLトレースは（ほとんど）使わない</a></li>
<li><a href="http://www.csus4.net/d/2011/03/24/display_cursor_howto/">DBMS_XPLAN.DISPLAY_CURSORの使い方とちょっとした落とし穴</a></li>
<li><a href="http://www.csus4.net/d/2011/04/30/check_cbo/">DISPLAY_CURSORでCBOの見積りミスを簡単に確認する</a></li>
</ul>

<p>それでは・・・</p>
]]></content:encoded>
			<wfw:commentRss>http://www.csus4.net/d/2011/10/14/oraclelovers2/feed/</wfw:commentRss>
		</item>
		<item>
		<title>フィルタ述語とアクセス述語 (実行計画の読み方#3)</title>
		<link>http://www.csus4.net/d/2011/06/30/predicate/</link>
		<comments>http://www.csus4.net/d/2011/06/30/predicate/#comments</comments>
		<pubDate>Thu, 30 Jun 2011 00:15:26 +0000</pubDate>
		<dc:creator>wr</dc:creator>
		
		<category><![CDATA[Oracle]]></category>

		<category><![CDATA[SQLチューニング]]></category>

		<guid isPermaLink="false">http://www.csus4.net/d/?p=612</guid>
		<description><![CDATA[さて、これまでで、実行計画のツリーのたどり方と、ツリーの構成要素である各オペレーションで
実行されている処理の概要がわかったと思います。

しかし、これだけの情報では、実行計画と実行されたSQLのWHERE条件を対応づけて理解することは
難しいです。（できなくはありませんが、かなり推測に頼る形になります。）

SQLのWHERE条件と対応付けるためには、フィルタ述語とアクセス述語に着目する必要があります。

Predicate Informationセクション

実行計画をDBMS_XPLAN.DISPLAY_CURSORで取得した場合、フィルタ述語とアクセス述語に関する情報は
Predicate Informationセクションに表示されます。

-----------------------------------------------------------------------------------------
&#124; Id  &#124; Operation                    &#124; Name     &#124; Rows  &#124; Bytes &#124; Cost (%CPU)&#124; Time     &#124;
-----------------------------------------------------------------------------------------
&#124;   0 &#124; SELECT STATEMENT    [...]]]></description>
			<content:encoded><![CDATA[<p>さて、これまでで、実行計画のツリーのたどり方と、ツリーの構成要素である各オペレーションで
実行されている処理の概要がわかったと思います。</p>

<p>しかし、これだけの情報では、実行計画と実行されたSQLのWHERE条件を対応づけて理解することは
難しいです。（できなくはありませんが、かなり推測に頼る形になります。）</p>

<p>SQLのWHERE条件と対応付けるためには、フィルタ述語とアクセス述語に着目する必要があります。</p>

<h3>Predicate Informationセクション</h3>

<p>実行計画をDBMS_XPLAN.DISPLAY_CURSORで取得した場合、フィルタ述語とアクセス述語に関する情報は
Predicate Informationセクションに表示されます。</p>

<pre><code>-----------------------------------------------------------------------------------------
| Id  | Operation                    | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |          |       |       |    20 (100)|          |
|   1 |  NESTED LOOPS                |          |    10 | 40120 |    20   (0)| 00:00:01 |
|*  2 |   TABLE ACCESS FULL          | PA       |     1 |  2004 |     9   (0)| 00:00:01 |
|   3 |   TABLE ACCESS BY INDEX ROWID| CH       |    10 | 20080 |    11   (0)| 00:00:01 |
|*  4 |    INDEX RANGE SCAN          | IDX_CHPA |    10 |       |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------

Predicate Information (identified by operation id): ←★
---------------------------------------------------

   2 - filter("PA"."PID"=1)
   4 - access("CH"."PID"=1)
</code></pre>

<p>Predicate Informationセクション内のフィルタ述語、アクセス述語の先頭には
オペレーション（ステップ）に対応するIdが記載されています。</p>

<p><span id="more-612"></span></p>

<h3>フィルタ述語の働き</h3>

<p>フィルタ述語は、Predicate Informationではfilter(&#8230;)と記載され、
行頭の番号に対応するオペレーションの実行時に、取得したデータから
対象データを抜粋（フィルタ）する処理が実行されたことを示します。</p>

<p>上記の実行計画では、Id=2 TABLE ACCESS FULL において
フィルタ述語 filter(&#8221;PA&#8221;.&#8221;PID&#8221;=1) が適用されていることがわかります。
これは、表PAを全表スキャンした後に、PA表のデータのうち、pa.pid = 1という
述語（条件）にマッチする行を抜粋したことになります。</p>

<pre><code>SELECT cid, cname, pa.pid, pname FROM ch, pa 
  WHERE ch.pid = pa.pid and pa.pid = 1
                            ^^^^^^^^^^
</code></pre>

<p>今回実行したSQL(から不要なヒントを除いて整形したもの)は、上記のとおりですが、
フィルタ述語 filter(&#8221;PA&#8221;.&#8221;PID&#8221;=1) の条件は、SQLのWHERE条件に記載された
pa.pid = 1 に対応していることがわかります。</p>

<h3>アクセス述語の働き</h3>

<p>アクセス述語は、Predicate Informationではaccess(&#8230;)と記載され、
行頭の番号に対応するオペレーションの実行時に、表示された述語を使用して
データにアクセスしたことを示します。
一般に、オペレーションが索引スキャン系(INDEX UNIQUE SCAN, INDEX RANGE SCAN)の場合に指定され、
索引をTraverseする（索引のroot → branch → leafとたどる)ときの索引列の検索条件に対応します。</p>

<p>上記の実行計画では、Id=4 INDEX RANGE SCAN において
アクセス述語 access(&#8221;CH&#8221;.&#8221;PID&#8221;=1) が適用されていることがわかります。
これは、索引IDX_CHPAの索引列CH.PIDに1という値を持つ索引エントリを探す
ことに相当します。</p>

<pre><code>SELECT cid, cname, pa.pid, pname FROM ch, pa 
  WHERE ch.pid = pa.pid and pa.pid = 1
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
</code></pre>

<p>アクセス述語 access(&#8221;CH&#8221;.&#8221;PID&#8221;=1) は、上記SQLのWHERE条件
ch.pid = pa.pid and pa.pid = 1 を数学的/算術的に変換したものであることが
わかります。（推移律 ： pa.pid=1であれば、ch.pid = pa.pidは ch.pid=1となる）</p>

<h3>WHERE条件とフィルタ述語、アクセス述語の対応関係</h3>

<p>このように、フィルタ条件、アクセス条件を確認すると、
それぞれのオペレーションにおいて、SQLのWHERE条件に対応したデータの絞込みが
行われているかをはっきりと理解することができます。</p>

<p>効率的なSQL実行の鉄則は、初期段階においてデータをできるだけ絞り込むことですので、
万が一、データが意図したように絞り込めていない場合は実行計画を再検討することに
なります。その際に、現行の実行計画がどのオペレーションにおいて、どのWHERE条件に
対応したデータの絞込みがなされているかを理解することが重要になります。</p>

<h3>フィルタ述語とアクセス述語の違い</h3>

<p>フィルタ述語とアクセス述語は、ともに述語に合致したデータのみが得られるという
点で似ていますが、処理効率の観点からは全く異なることに注意してください。</p>

<p>アクセス述語は一般に索引スキャン実行時に指定されますが、
アクセス述語に合致したデータにのみ選択的にアクセスします。
このため、一般にアクセスするブロック数を小さく抑えることができます。</p>

<p>一方、フィルタ述語は、ブロックにアクセスした後のデータを除外する際に
適用されます。アクセスした後にデータを絞り込む形になるため、
一般にアクセスするブロック数は大きくなりがちです。</p>

<p>したがって、どうしてもケースバイケースの側面はありますが、データの絞込みは
アクセス述語を使用する索引アクセスで行うことが一般に推奨されます。</p>

<h3>SQLトレースの実行計画ではフィルタ述語とアクセス述語が表示されないことに注意</h3>

<p>理由は不明ですが、SQLトレースの実行計画にはフィルタ述語とアクセス述語が表示されません。
上記のとおり、フィルタ述語とアクセス述語は実行計画内の各オペレーションの処理内容
を理解するために非常に有効な情報です。</p>

<p>このため、実行計画を確認する際は、フィルタ述語とアクセス述語が出力される
DBMS_PLAN.DISPLAY_CURSOR(または類似のファンクション)を使用することを
オススメします。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.csus4.net/d/2011/06/30/predicate/feed/</wfw:commentRss>
		</item>
		<item>
		<title>オペレーションの一覧と最低限覚えておくべきオペレーション (実行計画の読み方#2)</title>
		<link>http://www.csus4.net/d/2011/06/30/operations/</link>
		<comments>http://www.csus4.net/d/2011/06/30/operations/#comments</comments>
		<pubDate>Thu, 30 Jun 2011 00:00:34 +0000</pubDate>
		<dc:creator>wr</dc:creator>
		
		<category><![CDATA[Oracle]]></category>

		<category><![CDATA[SQLチューニング]]></category>

		<guid isPermaLink="false">http://www.csus4.net/d/?p=591</guid>
		<description><![CDATA[先のエントリの説明で、実行計画をいわば「形式的には読める(*1)」ようにはなりました。
しかし、実行計画が何をやっているのかという、意味的な観点では「理解できていない」はずです。
実行計画の処理内容を理解するためには、実行計画を構成するオペレーションの処理内容を理解する
必要があります。


(*1) 「たどれる」という表現のほうが近いかもしれませんが・・・


オペレーションの一覧

Oracle Databaseには非常に多くのオペレーションが存在し、
大部分のオペレーションについては、マニュアルの以下の箇所で説明されています。


10.2
11.1
11.2


最低限覚えておくべきオペレーション

全てのオペレーションに関して説明することは、現実的でないため、
先のエントリで説明した実行計画に含まれるオペレーションを説明します。
なお、このエントリに含まれるオペレーションは、非常に多くの実行計画で使用されうる、
非常に重要なものであり、最低限覚えておく必要があります。

-----------------------------------------------------------------------------------------
&#124; Id  &#124; Operation                    &#124; Name     &#124; Rows  &#124; Bytes &#124; Cost (%CPU)&#124; Time     &#124;
-----------------------------------------------------------------------------------------
&#124;   0 &#124; SELECT STATEMENT    [...]]]></description>
			<content:encoded><![CDATA[<p>先のエントリの説明で、実行計画をいわば「形式的には読める(*1)」ようにはなりました。
しかし、実行計画が何をやっているのかという、意味的な観点では「理解できていない」はずです。
実行計画の処理内容を理解するためには、実行計画を構成するオペレーションの処理内容を理解する
必要があります。</p>

<ul>
<li>(*1) 「たどれる」という表現のほうが近いかもしれませんが・・・</li>
</ul>

<h3>オペレーションの一覧</h3>

<p>Oracle Databaseには非常に多くのオペレーションが存在し、
大部分のオペレーションについては、マニュアルの以下の箇所で説明されています。</p>

<ul>
<li><a href="http://otndnld.oracle.co.jp/document/products/oracle10g/102/doc_cd/server.102/B19207-02/ex_plan.htm#59155">10.2</a></li>
<li><a href="http://otndnld.oracle.co.jp/document/products/oracle11g/111/doc_dvd/server.111/E05743-02/ex_plan.htm#sthref1154">11.1</a></li>
<li><a href="http://download.oracle.com/docs/cd/E16338_01/server.112/b56312/ex_plan.htm#i23461">11.2</a></li>
</ul>

<h3>最低限覚えておくべきオペレーション</h3>

<p>全てのオペレーションに関して説明することは、現実的でないため、
先のエントリで説明した実行計画に含まれるオペレーションを説明します。
なお、このエントリに含まれるオペレーションは、非常に多くの実行計画で使用されうる、
非常に重要なものであり、最低限覚えておく必要があります。</p>

<pre><code>-----------------------------------------------------------------------------------------
| Id  | Operation                    | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |          |       |       |    20 (100)|          |
|   1 |  NESTED LOOPS                |          |    10 | 40120 |    20   (0)| 00:00:01 |
|*  2 |   TABLE ACCESS FULL          | PA       |     1 |  2004 |     9   (0)| 00:00:01 |
|   3 |   TABLE ACCESS BY INDEX ROWID| CH       |    10 | 20080 |    11   (0)| 00:00:01 |
|*  4 |    INDEX RANGE SCAN          | IDX_CHPA |    10 |       |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
</code></pre>

<p><span id="more-591"></span></p>

<p>なお、上記の実行計画は</p>

<pre><code>SELECT /*+ FULL(PA) INDEX(CH idx_chpa) USE_NL(CH) LEADING(PA) */ 
       cid, cname, pa.pid, pname
   FROM ch, pa    WHERE ch.pid = pa.pid and pa.pid = 1
</code></pre>

<p>を実行したときのものです。(*2)</p>

<ul>
<li>(*2) 今回の説明の本筋ではないので気にしていただく必要はないのですが、説明に適した実行計画に誘導するために、Multi Join Key Pre-fetchingを無効化しています。</li>
</ul>

<h3>実行イメージ</h3>

<p>以下の文章では逐次オペレーションについて説明しますが、この図を参考に読んでいただくと理解しやすいはずです。</p>

<p><a href="http://www.csus4.net/d/wp-content/uploads/plan_ope.jpg"><img src="http://www.csus4.net/d/wp-content/uploads/plan_ope.jpg" alt="" title="plan operation" width="500" height="289" class="alignnone size-full wp-image-626" /></a></p>

<h3>TABLE ACCESS (FULL)</h3>

<p>実際の実行計画の実行順序に即して説明してゆきます。</p>

<p>この実行計画では、最初にId=2 TABLE ACCESS FULLが実行されます。</p>

<pre><code>|*  2 |   TABLE ACCESS FULL          | PA       |     1 |  2004 |     9   (0)| 00:00:01 |
</code></pre>

<p>TABLE ACCESS FULLは指定された表の全体をスキャン（フルスキャン）して、
表に格納された行データを取得するオペレーションです。
仕組みからわかるとおり、取得したい行の数が、表全体の行数に比べて多い場合には
効率的なデータアクセス方法ですが、少ない場合は非効率的です。</p>

<p>この実行計画では、PA表から1行のデータを得たとします。</p>

<h3>INDEX RANGE SCAN</h3>

<p>この実行計画では、次にId=4 INDEX RANGE SCAN が実行されます。</p>

<pre><code>|*  4 |    INDEX RANGE SCAN          | IDX_CHPA |    10 |       |     1   (0)| 00:00:01 |
</code></pre>

<p>Id=2 TABLE ACCESS FULL で得た pa.pid=1にマッチしたPA表の行に該当するデータを
CH表から取得するために実行しています。
索引をスキャンし、検索条件にマッチする索引列を含む行の識別子(ROWID)を得ます。</p>

<p>今回の実行計画では、索引列は一意ではないとしています。
この場合は、索引をスキャンするオペレーションの名称はINDEX RANGE SCAN であり、
複数行の識別子(複数のROWID)が返される場合があります。</p>

<p>なお、索引列が一意である場合、すなわち、索引が一意索引であり、検索条件が一意制約が
設定された索引列に対する等価条件である場合、
索引をスキャンするオペレーションの名称はINDEX UNIQUE SCANとなります。
このオペレーションでは、複数行の識別子(複数のROWID)が返されることはありません。
1つ(または0)のROWIDが返されます。</p>

<h3>TABLE ACCESS (BY INDEX ROWID)</h3>

<p>次に TABLE ACCESS (BY INDEX ROWID)が実行されます。</p>

<pre><code>|   3 |   TABLE ACCESS BY INDEX ROWID| CH       |    10 | 20080 |    11   (0)| 00:00:01 |
</code></pre>

<p>Id=4 INDEX RANGE SCAN
で得たROWID(のリスト)が示す行データを、CH表から取得します。
ROWIDは行のアドレスに相当する位置情報であるため、ROWIDがわかれば、行データが
どのブロックに格納しているかがわかります。</p>

<h3>NESTED LOOP</h3>

<p>Id=1 NESTED LOOPS
の子オペレーションの実行がすべて終了したため、
次は、Id=1    0   NESTED LOOPSが実行されます。</p>

<pre><code>|   1 |  NESTED LOOPS                |          |    10 | 40120 |    20   (0)| 00:00:01 |
</code></pre>

<p>NESTED LOOPSオペレーションは、複数の表の行データを結合する結合オペレーションの
1つで、文字通り入れ子ループのような処理モデルに従い、結合処理を実行します。</p>

<p>具体的には、上側の子オペレーションで得たデータに対して、対応するデータを
下側の子オペレーションを介して取得して結合する処理となります。
上側の子オペレーションで得たデータが複数行である場合、1つの行ごとに下側の子オペレーション
の処理が実行されるため、下側の子オペレーションは複数回実行される場合があります。</p>

<p>このような動作は、プログラミング言語における入れ子の制御ループに似ていることから、
NESTED LOOPによばれているようです。</p>

<pre><code>for (int i; i &lt; 10; i++){   → Id=2 TABLE ACCESS FULL に対応
  for (int j; j &lt; 10; j++{  → Id=3 TABLE ACCESS BY INDEX ROWIDに対応

  }
}
</code></pre>

<p>先の例では、上側の子オペレーションであるId=2 TABLE ACCESS FULLで
得られた行数が1でしたが、仮に2だった場合は、
Id=3 TABLE ACCESS BY INDEX ROWIDは2回実行されます。</p>

<h3>そのほかの結合オペレーション</h3>

<p>NESTED LOOP(ネステッドループ結合)以外の結合オペレーションとして、HASH JOIN (ハッシュ結合)、
MERGE JOIN(ソートマージ結合)の2つがありますが、これらについては追って説明します。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.csus4.net/d/2011/06/30/operations/feed/</wfw:commentRss>
		</item>
		<item>
		<title>JPOUGに参加させていただきました！</title>
		<link>http://www.csus4.net/d/2011/06/21/join_jpoug/</link>
		<comments>http://www.csus4.net/d/2011/06/21/join_jpoug/#comments</comments>
		<pubDate>Tue, 21 Jun 2011 08:00:55 +0000</pubDate>
		<dc:creator>wr</dc:creator>
		
		<category><![CDATA[Oracle]]></category>

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

		<guid isPermaLink="false">http://www.csus4.net/d/?p=619</guid>
		<description><![CDATA[インサイトテクノロジーの新久保さんの想いに共感し、Japan Oracle User Group - JPOUG にメンバーとして参加させていただきました！

Oracle Database Userのみなさんに役立つ活動を行っていきたいと思います！
何かご意見がありましたら、twitterやblogのコメント欄で頂戴できればうれしいです！
]]></description>
			<content:encoded><![CDATA[<p>インサイトテクノロジーの新久保さんの想いに共感し、<a href="http://www.jpoug.org/">Japan Oracle User Group - JPOUG</a> にメンバーとして参加させていただきました！</p>

<p>Oracle Database Userのみなさんに役立つ活動を行っていきたいと思います！
何かご意見がありましたら、twitterやblogのコメント欄で頂戴できればうれしいです！</p>
]]></content:encoded>
			<wfw:commentRss>http://www.csus4.net/d/2011/06/21/join_jpoug/feed/</wfw:commentRss>
		</item>
		<item>
		<title>実行計画のツリーのたどり方 (実行計画の読み方#1)</title>
		<link>http://www.csus4.net/d/2011/06/20/traverse_plan_tree/</link>
		<comments>http://www.csus4.net/d/2011/06/20/traverse_plan_tree/#comments</comments>
		<pubDate>Mon, 20 Jun 2011 01:00:13 +0000</pubDate>
		<dc:creator>wr</dc:creator>
		
		<category><![CDATA[Oracle]]></category>

		<category><![CDATA[SQLチューニング]]></category>

		<guid isPermaLink="false">http://www.csus4.net/d/?p=586</guid>
		<description><![CDATA[これまでのエントリに記載してきたように、実行計画は階層的なツリー構造で表現
されます。
本エントリでは、実行計画の読み方のfirst stepとして、
実際の処理順序に即したツリー構造のたどり方を説明します。

SQL&#62; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'LAST'));

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------
SQL_ID  dvv5bah5b4k51, child number 1
-------------------------------------
SELECT /*+ FULL(PA) INDEX(CH idx_chpa) USE_NL(CH) LEADING(PA) */ cid,
cname, pa.pid, pname    FROM ch, pa    WHERE ch.pid = pa.pid and pa.pid
= 1

Plan hash value: 3514264536

-----------------------------------------------------------------------------------------
&#124; Id  &#124; Operation          [...]]]></description>
			<content:encoded><![CDATA[<p>これまでのエントリに記載してきたように、実行計画は階層的なツリー構造で表現
されます。
本エントリでは、実行計画の読み方のfirst stepとして、
実際の処理順序に即したツリー構造のたどり方を説明します。</p>

<pre><code>SQL&gt; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'LAST'));

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------
SQL_ID  dvv5bah5b4k51, child number 1
-------------------------------------
SELECT /*+ FULL(PA) INDEX(CH idx_chpa) USE_NL(CH) LEADING(PA) */ cid,
cname, pa.pid, pname    FROM ch, pa    WHERE ch.pid = pa.pid and pa.pid
= 1

Plan hash value: 3514264536

-----------------------------------------------------------------------------------------
| Id  | Operation                    | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |          |       |       |    20 (100)|          |
|   1 |  NESTED LOOPS                |          |    10 | 40120 |    20   (0)| 00:00:01 |
|*  2 |   TABLE ACCESS FULL          | PA       |     1 |  2004 |     9   (0)| 00:00:01 |
|   3 |   TABLE ACCESS BY INDEX ROWID| CH       |    10 | 20080 |    11   (0)| 00:00:01 |
|*  4 |    INDEX RANGE SCAN          | IDX_CHPA |    10 |       |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("PA"."PID"=1)
   4 - access("CH"."PID"=1)


24 rows selected.
</code></pre>

<h3>実行計画のツリー構造とオペレーションの親子関係</h3>

<p>実行計画は、一般に複数のオペレーションから構成されます。オペレーションは、親子関係に
したがってインデントして整形されたツリー構造となります。</p>

<p>たとえば、上記の実行計画は、NESTED LOOPS, TABLE ACCESS FULL などのオペレーション
から構成されます。(オペレーションの種類と処理内容については次のエントリで説明します。）</p>

<p>オペレーションの親子関係についてですが、
Id=1 NESTED LOOPSは Id=2 TABLE ACCESS FULLと、Id=3 TABLE ACCESS BY INDEX ROWID
の親となります。同様に Id=3 TABLE ACCESS BY INDEX ROWID
Id= 4 INDEX RANGE SCAN の親となります。</p>

<pre><code>                Id=0 SELECT STATEMENT
                       ↑
                       │行ソース
                       │
                Id=1 NESTED LOOPS 
                     ↑  ↑
 行ソース┌─────┘  └─────┐行ソース
         │                          │
Id=2 TABLE ACCESS FULL      Id=3 TABLE ACCESS BY INDEX ROWID
                                     ↑
                                     │行ソース
                                     │
                            Id=4 INDEX RANGE SCAN
</code></pre>

<p>それぞれのオペレーションは、行ソースとよばれる表から取得した行データ（のサブセット）を出力します。
親オペレーションは子オペレーションの行ソースを入力として処理を行います。</p>

<p>概念的な説明だけではわかりにくいので、先の実行計画がどのように処理されるかを
イメージしながら、読み方を説明してみましょう。</p>

<p><span id="more-586"></span></p>

<h3>実行計画で一番最初に実行されるオペレーションを探す</h3>

<p>まず、この実行計画で一番最初に実行される(*1) オペレーションを探します。
最も最上位のオペレーション(Id=0 SELECT STATEMENT)にポイントしてから、そのオペレーションの
子オペレーションをたどります。
子オペレーションが2つ以上ある場合は、上側に表記されたオペレーションをたどります。
子の子、子の子の子、とインデントされたオペレーションを順にたどってゆき、
子がなくなった時点でポイントしていたオペレーションが、
実行計画で一番最初に実行されるオペレーションです。</p>

<p>先の実行計画の例において、一番最初にオペレーションを特定するまでの手順は以下の
とおりです。</p>

<ul>
<li>1&#46; 最も最上位のオペレーション(Id=0 SELECT)をポイント</li>
<li>2&#46; Id=0 SELECTの子オペレーションはId=1 NESTED LOOPSだけなので、NESTED LOOPSをポイント</li>
<li>3&#46; Id=1 NESTED LOOPSの子オペレーションとして、2つのオペレーション
Id=2 TABLE ACCESS FULL と
Id=3 TABLE ACCESS BY INDEX ROWID があるが、上側に表示されている
Id=2 TABLE ACCESS FULLをたどる。</li>
<li>4&#46; Id=2 TABLE ACCESS FULL には、子オペレーションがないため、
このオペレーションがこの実行計画で最初に実行されるオペレーションとなる</li>
</ul>

<p>一番深くインデントされたオペレーションが必ずしも一番最初に実行される
わけではないことに注意が必要です。
上記の例でも、一番深くインデントされたオペレーションである
Id=4 INDEX RANGE SCAN は一番最初に実行されるオペレーションではありません。</p>

<ul>
<li>(*1)「実質的な意味で」一番最初に実行されるオペレーションという意味です。
形式的には、Id=0のSELECT STATEMENTが一番最初に実行されるオペレーションですが、この観点は理解するうえであまり意味がないからです。</li>
</ul>

<h3>以後のオペレーション実行順序</h3>

<p>さて、最初に実行されるオペレーションが  Id=2 TABLE ACCESS FULL
であることはわかりました、以降、どのような順序でオペレーションが実行される
のでしょうか。順に追っていきましょう。</p>

<ul>
<li>5&#46; Id=2 TABLE ACCESS FULL は、PA表をテーブルスキャン（全行取得）する
オペレーションであり、取得した結果を親オペレーションId=1 NESTED LOOPに
渡す。</li>
<li>6&#46; Id= 1 NESTED LOOP は、自分の子オペレーションのうち、次に実行すべき
オペレーションを探す。ここでは、Id= 3 TABLE ACCESS BY INDEX ROWIDが
未実行であるため、Id= 3 TABLE ACCESS BY INDEX ROWID をポイントする。</li>
<li>7&#46; Id= 3 TABLE ACCESS BY INDEX ROWID は自分の子オペレーションである、
Id= 4 INDEX RANGE SCAN をポイントする。</li>
<li>8&#46; Id= 4 INDEX RANGE SCAN には子オペレーションがないため、
Id= 4 INDEX RANGE SCAN の処理を実行する。
索引IDX_CHPAをレンジスキャン（範囲検索）し、表に格納された行の識別子
である、ROWIDのリストを得て、取得した結果を親オペレーション
Id= 3 TABLE ACCESS BY INDEX ROWID に渡す。</li>
<li>9&#46; Id= 3 TABLE ACCESS BY INDEX ROWI Dは
Id= 4 INDEX RANGE SCAN より得たROWIDの
リストに従い、表から行データを取得し、取得した結果を親オペレーション
Id= 1 NESTED LOOPに渡す。</li>
<li>10&#46; Id= 1 NESTED LOOP のすべての子オペレーションの実行が完了したため、
自オペレーションの処理である Nested Loop 結合処理を実行して、結果を
親オペレーションId=0 SELECTに渡す。</li>
<li>11&#46; Id=0 SELECTは擬似的なオペレーションであり、実際の処理は行わないため、ここで終了</li>
</ul>

<p>このような順序となります。</p>

<h3>ルール化するならば</h3>

<p>先に説明した手順をルール化するならば、以下のようにまとめられます。
（わかりやすくするため厳密性を犠牲にしています。）</p>

<ul>
<li>1&#46; 自オペレーションの処理は、すべての子オペレーションの処理が完了してから実行される。</li>
<li>2&#46; 子オペレーションがない場合、自オペレーションを実行できる。</li>
<li>3&#46; あるオペレーションに子オペレーションが複数ある場合、上側に記載された子
オペレーションが先に実行される。</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.csus4.net/d/2011/06/20/traverse_plan_tree/feed/</wfw:commentRss>
		</item>
		<item>
		<title>実行計画の読み方</title>
		<link>http://www.csus4.net/d/2011/06/20/how_to_read_explain_plan/</link>
		<comments>http://www.csus4.net/d/2011/06/20/how_to_read_explain_plan/#comments</comments>
		<pubDate>Sun, 19 Jun 2011 23:00:35 +0000</pubDate>
		<dc:creator>wr</dc:creator>
		
		<category><![CDATA[Oracle]]></category>

		<category><![CDATA[SQLチューニング]]></category>

		<guid isPermaLink="false">http://www.csus4.net/d/?p=582</guid>
		<description><![CDATA[これまでのエントリで、DBMS_XPLAN.DISPLAY_CURSORをつかってV$SQL_PLAN
から実行計画を取得する方法をオススメしてきました。
この方法は、手軽であり、かつ、SQLトレースやEXPLAIN PLANの問題点に対処できる
優れた方法であることがお分かりいただけたかと思います。

しかし、当たり前の話ですが、実行計画を取得できたとしても、読めなければ意味がありません。
このため、取得した実行計画の読み方をこれからいくつかのエントリで説明したいと思います。

以下の構成で進める予定です。（エントリ記載次第、リンクを張る予定）


実行計画のツリーのたどり方
オペレーションの一覧と最低限覚えておくべきオペレーション
フィルタ述語とアクセス述語
結合の動作イメージとオペレーション


自身の経験上、実行計画の読み方は一度の説明で理解しにくいようです。
このため、一連のエントリでは、わざと同じようなことを何度も繰り返し説明するような
形にしています。
]]></description>
			<content:encoded><![CDATA[<p>これまでのエントリで、DBMS_XPLAN.DISPLAY_CURSORをつかってV$SQL_PLAN
から実行計画を取得する方法をオススメしてきました。
この方法は、手軽であり、かつ、SQLトレースやEXPLAIN PLANの問題点に対処できる
優れた方法であることがお分かりいただけたかと思います。</p>

<p>しかし、当たり前の話ですが、実行計画を取得できたとしても、読めなければ意味がありません。
このため、取得した実行計画の読み方をこれからいくつかのエントリで説明したいと思います。</p>

<p>以下の構成で進める予定です。（エントリ記載次第、リンクを張る予定）</p>

<ul>
<li><a href="http://www.csus4.net/d/2011/06/20/traverse_plan_tree/">実行計画のツリーのたどり方</a></li>
<li><a href="http://www.csus4.net/d/2011/06/30/operationsoperations/">オペレーションの一覧と最低限覚えておくべきオペレーション</a></li>
<li><a href="http://www.csus4.net/d/2011/06/30/predicate/">フィルタ述語とアクセス述語</a></li>
<li>結合の動作イメージとオペレーション</li>
</ul>

<p>自身の経験上、実行計画の読み方は一度の説明で理解しにくいようです。
このため、一連のエントリでは、わざと同じようなことを何度も繰り返し説明するような
形にしています。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.csus4.net/d/2011/06/20/how_to_read_explain_plan/feed/</wfw:commentRss>
		</item>
		<item>
		<title>SQLチューニングアドバイザの代用品としての動的サンプリング</title>
		<link>http://www.csus4.net/d/2011/05/06/dynamic_sampling/</link>
		<comments>http://www.csus4.net/d/2011/05/06/dynamic_sampling/#comments</comments>
		<pubDate>Fri, 06 May 2011 00:00:21 +0000</pubDate>
		<dc:creator>wr</dc:creator>
		
		<category><![CDATA[Oracle]]></category>

		<category><![CDATA[SQLチューニング]]></category>

		<guid isPermaLink="false">http://www.csus4.net/d/?p=574</guid>
		<description><![CDATA[先のエントリ 
で、実行計画の見積もりミスの可能性を調べるため、CBOの見積もり行数と実行時行数の
差異をチェックする方法をお伝えしました。
実際にCBOの見積もり行数と実行時行数の差異が大きいSQLを見つけた場合は、
現在使用している実行計画が最適かどうか、最適な実行計画はどのようなものかを
検討する必要が出てきます。

しかし、この作業は簡単なものではありません。
先のエントリ 
の例は、1つのテーブルにのみアクセスするきわめてシンプルなものであり、
テーブルスキャン(TABLE ACCESS FULL)
よりもインデックススキャン (INDEX RANGE SCAN)
が効率的であるとすぐにわかりました。
しかし、通常のアプリケーションではSQLはもっと複雑であり、
最適な実行計画の検討は、Oracle Databaseに関するSQLチューニングスキルが必要であり、時間もかかる作業です。

Oracle Database 9.2 以前など、アドバイザ機能が充実していなかったバージョンを
使用していたときは、スキルを持ったデータベースエンジニアが、さまざまな角度から
検討し、最適と思われる実行計画を検討していたと思います。
この作業は、実際に効果が得られるかどうか不透明なわりに、時間と労力を要する非効率的なものでした。
チューニング作業は、時間をかければかけただけ、必ず改善されるという保障があるわけではないという
側面があるからです。

Oracle Database 10g以後では、アドバイザ機能が充実し、SQLチューニングアドバイザ
を活用して、Oracle Database が自動的に最適な実行計画を作成してくれるように
なっており、作業コストを大幅に削減できます。
しかし、SQLチューニングアドバイザを使用するためには Enterprise Edition の利用に
くわえて、別売のオプション機能 Diagnostic Pack と Tuning Packが必要であるため、
使用できる人が限られるのが現実ではないでしょうか。

動的サンプリングによる最適な実行計画検討の自動化

実は、動的サンプリングという機能を使うことで、SQLチューニングアドバイザが使用で
きない場合でも、最適と思われる実行計画の検討をOracle Database任せにすることが
できます。


動的サンプリングは、SQLの実行前に、SQLがアクセスするテーブルのデータをサンプリングし、
サンプリングした結果を元にCBOがSQLの実行計画を作成する機能です。
通常の場合、すなわち動的サンプリングが実行されない場合、
CBOはオプティマイザ統計を元に実行計画を作成します。オプティマイザ統計は
データの特性を集約したサマリ情報
（具体的には行の平均長や列値の最小値・最大値、ヒストグラムなど）に過ぎないため、
仮にオプティマイザ統計が最新の状態であっても、CBOのコスト予測が外れて最適な
実行計画が作成されない場合がないのは、先のエントリで示したとおりですが、
実際のデータをサンプリングすれば、予測が外れる可能性を大幅に減らすことが
できます（実際にデータを先読みしているので、予測が当たるのは当たり前といえば当たり前ですが・・・）。

では、初期化パラメータOPTIMIZER_DYNAMIC_SAMPLING を指定して、動的サンプリングを
有効にしてから、先のエントリのSQLを実行し、Oracle Database が最適と判断した実行計画を
見てみましょう。

なんと！（わざとらしいですね）想定どおりのインデックススキャン(INDEX RANGE SCANオペレーション)
を用いた実行計画が選択されました！

SQL&#62; alter session set statistics_level=ALL;
セッションが変更されました。

SQL&#62; alter session set OPTIMIZER_DYNAMIC_SAMPLING=10;
セッションが変更されました。

SQL&#62; SELECT sum(val1) FROM tbl0 WHERE flg1 = 'X' AND flg2 = 'X';
 SUM(VAL1)
----------
     [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.csus4.net/d/2011/04/30/check_cbo/">先のエントリ</a> 
で、実行計画の見積もりミスの可能性を調べるため、CBOの見積もり行数と実行時行数の
差異をチェックする方法をお伝えしました。
実際にCBOの見積もり行数と実行時行数の差異が大きいSQLを見つけた場合は、
現在使用している実行計画が最適かどうか、最適な実行計画はどのようなものかを
検討する必要が出てきます。</p>

<p>しかし、この作業は簡単なものではありません。
<a href="http://www.csus4.net/d/2011/04/30/check_cbo/">先のエントリ</a> 
の例は、1つのテーブルにのみアクセスするきわめてシンプルなものであり、
テーブルスキャン(TABLE ACCESS FULL)
よりもインデックススキャン (INDEX RANGE SCAN)
が効率的であるとすぐにわかりました。
しかし、通常のアプリケーションではSQLはもっと複雑であり、
最適な実行計画の検討は、Oracle Databaseに関するSQLチューニングスキルが必要であり、時間もかかる作業です。</p>

<p>Oracle Database 9.2 以前など、アドバイザ機能が充実していなかったバージョンを
使用していたときは、スキルを持ったデータベースエンジニアが、さまざまな角度から
検討し、最適と思われる実行計画を検討していたと思います。
この作業は、実際に効果が得られるかどうか不透明なわりに、時間と労力を要する非効率的なものでした。
チューニング作業は、時間をかければかけただけ、必ず改善されるという保障があるわけではないという
側面があるからです。</p>

<p>Oracle Database 10g以後では、アドバイザ機能が充実し、SQLチューニングアドバイザ
を活用して、Oracle Database が自動的に最適な実行計画を作成してくれるように
なっており、作業コストを大幅に削減できます。
しかし、SQLチューニングアドバイザを使用するためには Enterprise Edition の利用に
くわえて、別売のオプション機能 Diagnostic Pack と Tuning Packが必要であるため、
使用できる人が限られるのが現実ではないでしょうか。</p>

<h3>動的サンプリングによる最適な実行計画検討の自動化</h3>

<p>実は、動的サンプリングという機能を使うことで、SQLチューニングアドバイザが使用で
きない場合でも、最適と思われる実行計画の検討をOracle Database任せにすることが
できます。</p>

<p><span id="more-574"></span>
動的サンプリングは、SQLの実行前に、SQLがアクセスするテーブルのデータをサンプリングし、
サンプリングした結果を元にCBOがSQLの実行計画を作成する機能です。
通常の場合、すなわち動的サンプリングが実行されない場合、
CBOはオプティマイザ統計を元に実行計画を作成します。オプティマイザ統計は
データの特性を集約したサマリ情報
（具体的には行の平均長や列値の最小値・最大値、ヒストグラムなど）に過ぎないため、
仮にオプティマイザ統計が最新の状態であっても、CBOのコスト予測が外れて最適な
実行計画が作成されない場合がないのは、先のエントリで示したとおりですが、
実際のデータをサンプリングすれば、予測が外れる可能性を大幅に減らすことが
できます（実際にデータを先読みしているので、予測が当たるのは当たり前といえば当たり前ですが・・・）。</p>

<p>では、初期化パラメータOPTIMIZER_DYNAMIC_SAMPLING を指定して、動的サンプリングを
有効にしてから、先のエントリのSQLを実行し、Oracle Database が最適と判断した実行計画を
見てみましょう。</p>

<p>なんと！（わざとらしいですね）想定どおりのインデックススキャン(INDEX RANGE SCANオペレーション)
を用いた実行計画が選択されました！</p>

<pre><code>SQL&gt; alter session set statistics_level=ALL;
セッションが変更されました。

SQL&gt; alter session set OPTIMIZER_DYNAMIC_SAMPLING=10;
セッションが変更されました。

SQL&gt; SELECT sum(val1) FROM tbl0 WHERE flg1 = 'X' AND flg2 = 'X';
 SUM(VAL1)
----------
         1

SQL&gt; select * from table(DBMS_XPLAN.display_cursor('42fxsw7fcxuht',0, 'ALL ALLSTATS LAST'));

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  42fxsw7fcxuht, child number 0
-------------------------------------
SELECT sum(val1) FROM tbl0 WHERE flg1 = 'X' AND flg2 = 'X'

Plan hash value: 1204532613

------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name      | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |           |      1 |        |       |     2 (100)|          |      1 |00:00:00.01 |       3 |
|   1 |  SORT AGGREGATE              |           |      1 |      1 |     7 |            |          |      1 |00:00:00.01 |       3 |
|   2 |   TABLE ACCESS BY INDEX ROWID| TBL0      |      1 |      1 |     7 |     2   (0)| 00:00:01 |      1 |00:00:00.01 |       3 |
|*  3 |    INDEX RANGE SCAN          | IDX0_TBL0 |      1 |      1 |       |     1   (0)| 00:00:01 |      1 |00:00:00.01 |       2 |
------------------------------------------------------------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$1
   2 - SEL$1 / TBL0@SEL$1
   3 - SEL$1 / TBL0@SEL$1

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("FLG1"='X' AND "FLG2"='X')

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - (#keys=0) SUM("VAL1")[22]
   2 - "VAL1"[NUMBER,22]
   3 - "TBL0".ROWID[ROWID,10]

Note
-----
   - dynamic sampling used for this statement (level=10) ←★


38行が選択されました。
</code></pre>

<p>動的サンプリングが実行された場合は、Noteセクションにその旨の表示がされることに
注意してください。ここで動的サンプリングの実行有無をチェックできます。</p>

<p>動的サンプリングレベルには0から10を指定でき、マニュアルでは基本的にサンプリング
対象のブロック数に影響するような表記があります。
しかし、ブロック数だけではなく、動的サンプリングの実行有無の
判断にも使用されるようです（小さいレベルを指定すると動的サンプリングが実行されないような動作が見られる場合もある模様・・・詳細不明）。</p>

<p>動的サンプリングを用いて作成された実効計画が適切であると判断できる場合は、
この実行計画に近づくように、元のSQLにヒントを追加したりするなどして、
元のSQLがこの実行計画で実行されるようにするよう誘導することもできます。</p>

<p>なお、動的サンプリングの結果は共有プールに保管され、再利用されるようです。
毎回動的サンプリングを実行するのはナンセンスですので、妥当な動作であると思われますが、
再利用のロジックが明確でないため、いわゆるアプリケーションからのSQL実行時において
動的サンプリングを使用することには十分な検討が必要です。（特にサンプリングレベルの設定）</p>

<h3>ではSQLチューニングアドバイザは不要か？</h3>

<p>動的サンプリングは非常に便利な機能です。
しかし、動的サンプリングがあれば、SQLチューニングアドバイザが不要かというと
そんなことはありません。
SQLチューニングアドバイザでは、アドバイザ結果をSQLプロファイルして提供すること
があります。SQLプロファイルは最適な実行計画を選ぶことを可能にする補足的な統計であり、
ヒントと異なり、実行計画を完全に固定する情報ではありません。
したがって、データ量が増減して最適な実行計画が変化した場合でも、それに追従することができます。
ヒントではこのような柔軟な処理は実現できません（ターゲットとする実行計画が変化するたびに、
それに応じてヒントを書き換える必要があります）。</p>

<p>また、動的サンプリングを用いる方法では、実行計画の誘導作業を自動化することが
できません。SQLにヒントを埋め込む作業は、SQLをコーディングするエンジニアが行う必要があります。</p>

<p>したがって、あくまでも動的サンプリングを用いる方法は、「SQLチューニングアドバイザ
が利用できない環境で、やむを得ず使用する方法」と位置づけることが妥当でしょう。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.csus4.net/d/2011/05/06/dynamic_sampling/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>

