« 2006年12月 | トップページ | 2007年6月 »

2007年1月

2007年1月14日 (日)

時間のかかる処理のタイムアウト

たまに、Oracleである一定の時間以上かかる処理を終了させるには?なんて質問を見受けれられるが、ここでは、そのサーバー側での設定方法を。これをサーバー側で設定するには、Oracleのプロファイルというものを利用する。プロファイルとはユーザーへのリソースの割り当ての制限やパスワードの制限を行うもので、これを使用すれば、一定時間以上かかる処理を自動的に終了させることができる。で、通常CREAT USER文でのユーザー作成時に特に使用するプロファイルを指定していなければ、そのユーザーにはDEFAULTプロファイルというプロファイルが割り当てられる。で、DBA_PROFILESデータディクショナリでDEFAULTプロファイルの内容を取得したのが下の図である。

Profile_2

上の図のように、プロファイルで様々なタイプのリソース・パスワード制限ができるが、ここでは、CPU_PER_CALLを使う。上の図では、CPU_PER_CALLの値がUNLIMITEDつまり無制限(制限しない)になっているのでこれを適切な値に変えればよい。ALTER PROFILE文で既存のプロファイルの内容を変えることができるが、詳しくはマニュアルを参照。

ここでは、事前定義済みのDEFAULTプロファイルを紹介したが、DBA_USERSのPROFILE列を見てわかるように、データベース作成時などに作成されるほとんどのユーザーにDEFAULTプロファイルが割り当てら、DEFAULTプロファイルを変更すると大きな影響が発生するので、実際使用する場合は、CREATE PROFILE文を新たなプロファイルを作成し、それを使用した方がいいと思う。

2007年1月12日 (金)

スクロールバーあれこれの続き

前回、ScrollBar関係のAPIを使って制御する時、毎回、頭を痛めると書いたが、表現が適切じゃなかった。ただ自分が使い方を誤解していたのである。で、初めて使う人にやりがちな決め方(自分だけかも知れない)を書いてみる。というか、非常にかったるい話です。

テキストをM行表示する場合を考えてみよう。この時、ウィンドウのクライアント領域の高さの制限からN(N<=M)行しか表示できないとする。まず、範囲(nMinとnMax)を決めると思うので範囲を決めてみる。(M-N)行表示されていない部分があるので、(M-N)+1通りの状態を表せればよいので、例えば、nMin=0、nMax=M-Nとする。で、これで位置についてはよさそうなので、次はページを決めてみる。この場合、全体M行のうちN行つまりページサイズが全体のN/Mになればよいので、nPage=全体*N/M=(M-N + 1)*N/Mでいいかなと・・

つまり、この場合、

  • nMin=0
  • nMax=M-N
  • nPage=(M-N + 1)*N/M

になる。で、具体的に、10行(M=10)表示するとしてクライアント領域に5行(N=5)しか表示できないとして、代入してみると、

  • nMin = 0
  • nMax = 5
  • nPage =3

となり、ちょうど、ページサイズが3と全体6(=5-0+1)の半分になっていて、これでいいのかななんて考える。で、今度はM=10、N=6としてみると、うぉ。nPageの型が整数なんだけど、整数にならない。切り捨て・切り上げても問題ないのかなぁ・・・と。こうやって、ドツボにはまったのである。

そもそも使い方が間違っていて、範囲の決め方が問題なのである。様々なサイトを見ると、nMinとnMaxにスクロール範囲を指定すればよいなどと書かれているが、語弊があるかもしれないが、表示したい内容全体の量を*範囲*で指定するのである。この場合、M行表示したいので、nMin=0とすれば、nMax=M-1(nMin=1とすれば、nMax=10、nMin=5とすれば、nMax=14・・・どの場合も、nMax - nMin + 1=M=一定)でいいのである。でページサイズには、実際に表示できる量つまりこの場合N行なので、nPage=Nになる。つまり、

  • nMin=0
  • nMax=M - 1
  • nPage=N

でいいのである。で、先ほどど同じように、M=10、N=5としてみると

  • nMin=0
  • nMax=9
  • nPage=5

になる。でポイントはここからだ。この場合実際表示されていない行は5行なのに、nMin=0、nMax=9だから、サムの位置が0から9と変化できて問題あるんじゃ?と思うだろう。だが、実際、SetScrollInfoやSetScrollPosでサムの位置だけを変えてあげると、0から5までしか移動できないのである。つまり、サムが取れる位置はページサイズの影響をうけるのだ。サムの位置の最大値=nMaxではなく

サムの位置の最大値=(nMax - nMin + 1) - nPageになる。

これを理解して初めて、SCROLLINFO構造体のnMin、nMax、nPosそしてnPageに何を設定すればいいか理解できた。ちなみに、今回の例では行単位で考えたが、ピクセル単位で考えても同じことが言える。疲れた。

スクロールバーあれこれ

今回はスクロールバーのお話。Windowsには主に2種類のスクロールバーがある。

  • 標準スクロールバー
  • スクロールバーコントール

である。標準スクロールバーは別名ビルインスクロールバーと言われ、ウィンドウハンドルを持つウィンドウの一部として表示されるスクロールバーである。スクロールバーコントロールは、EDITクラスのエディットボックスやBUTTONクラスのプッシュボタンなどのシステムによって提供される事前定義済みのクラスのウィンドウである(つまり、それ自体でウィンドウハンドルを持つ)。ちなみに、標準スクロールバーはAPIのCreateWindowでウィンドウを作成するときに、ウィンドウスタイルとしてWS_HSCROLL、WS_VSCROLLを指定するか、ウィンドウ表示後、ShowScrollBarを使って表示できる。スクロールバーコントロールはCreateWindowでウィンドウを作成するときに指定する、ウィンドウクラス名をSCROLLBARにすればよい。

Scrollbarcontrol

で、このスクロールバーをAPIを使って制御する時に、毎回、自分が頭を痛めることは、スクロールの範囲、サム(つまみ)の位置、ページのサイズの取り方である。慣れれば、難しくはないと思うが・・具体的に言うとGetScrollInfoやSetScrollInfoで指定するSCROLLINFO構造体の中身のことである。ちなみに、この構造体のnMinからnMaxまでがスクロールの範囲、nPosがサムの位置、nPageがページのサイズを表す。

ページとは、、現在表示されているコンテンツがコンテンツ全体のうち、どれくらいの割合になるかを示す量である。例えば、上の図では、水平スクロールバーの横幅に対するサムの横幅の割合がだいたい目算で1/10くらいなので、ユーザーは現在、実際に表示されているコンテンツは全体の1/10くらいなんだなと推測できる。

で、続く・・・・

2007年1月11日 (木)

Iである

Iである。今回はこのIに焦点を当ててみる。アイとは何ぞや?ってことだが、MSDNのフォント・テキスト関連のAPIの一覧をみると、末尾にIがつくものがいくつかみつかる。GetCharWidthIやGetCharABCWidthIやGetTextExtentPointIなどである。説明を見ればわかるとおり、グリフインデックス(GlphyIndex)のIである(と思う。)

文字列を描画するときに、ExtTextOutなどのAPIに文字コード(UnicodeやShift-JISなど)で表現した文字列を渡して描画するのが一般的だが、直接、フォント内の各グリフのインデックスを使って描画することもできる。まずは、グリフインデックスの取得方法であるが、GetGlyphIndicesを使って、指定した文字列のグリフインデックスの配列を取得できる。このとき、第5引数のフラグflにGGI_MARK_NONEXISTING_GLYPHSを指定すると、フォントにグリフが存在しない場合、0xFFFFが指定しない場合0x0000が返ってくる。この配列を使い、文字コードではなく、グリフインデックスを使って描画したイメージが下の図の下の文字列である。

Indices

ちなみに、グリフインデックスを使用する場合、ExtTextOutの第3引数にETO_GLYPH_INDEXを指定する。また、Tahomaという欧文フォントを使用している。上の文字列はいつも通りの文字コードを使って同じ文字列をExtTextOutで描画したものである。もう何が起きているのかわかると思うが、GetGlyphIndicesを使用して取得するとフォントリンク機能が働かないのである。よって、「あいうえお」の文字列に対応するグリフインデックスが「0xFFFFまたは0x0000」になっている。それで、文字化けが起こったのである。それだけである・・・・

ちなみに、GetGlyphIndicesのグリフインデックスの配列を受け取る第4引数の型がLPWORDである。つまり、各インデックスは2バイトでAPIの仕様の制限かフォントファイルの制限かわからないが、フォントに収録できる文字数は2バイトまでなのかなぁ・・なんて推測してみたり。と、これで思い出したのが、サロゲートである。サロゲート文字は1文字を2ワード(4バイト)で表現する文字であるが、GetCharABCWidthなどで指定する文字コードの型がUINTになっていて、これらのAPIがサロゲートを正しく処理するかは、おいといて、インターフェースを変えずにサロゲートも渡せるよう既になっているなと安堵してみたり。

2007年1月10日 (水)

GetTextExtentExPointの締めくくり

えらい、まとまりのない文章になってしまった。前回でいきなり問題にぶつかったとかいてるが、要は自前でGetTextExtentExPointを使いクリッピングを行った方が速いか遅いかだ。ということで、パフォーマンスをとってみた。文字数10240の文字列(Unicodeだから20KBytes)をウィンドウのクライアント領域の左隅から計1万回描画してみた。

  • GDIのクリッピングに任せた場合:約4100ms
  • 自前でGetTextExtentExPointでクリッピングした場合:約5600ms

ははは。って感じである。逆に遅くなった・・・今回、GetTextExtentExPointを呼び出す時に渡すnMaxExtentにクライアント領域の幅ではなくクライアント領域の幅+マージンを渡している。なぜなら、今回はワードラップを行うのではなく、文字列を切り捨てるためにGetTextExtentExPointを呼び出しているので、クライアント領域の幅を渡すと、場合によっては、クライアント領域の一番右側に表示される文字がかって切り捨てられて、GDIのクリッピングに任せた場合と結果が異なってしまうからだ。マージンをどれくらい渡すかだが、GetTextMetricで返される構造体のtmAveCharWidth(平均文字幅)の3倍以上とっとけば、結果がずれることはほぼないだろう。ExtTextOutの呼び出しは前々回と同じように、GetTextExtentExPointで返されたlpnFitを文字数として、ExtTextOutの第7引数cbCountに渡している。

ところで、やはり、自前クリッピングの方が遅くなってるのは、前回書いたように、GetTextExtentExPointの呼び出しで毎回文字列全体の寸法(lpSize)が求められているためだろう・・・ちなみに、触れずにきたが、この話では、固定ピッチフォントと可変ピッチの両方を想定しているので、単純に幅の計算や切り捨てる部分の計算できない。

というか、巨大な長さの文字列を描画するはめにはなるかもしれんが、そんな文字列を現実問題1万回描画するシチュエーションが見つからない。描画対象が画面の場合、少なくとも縦方向の解像度数以上描画しても意味ないし、縦1200ピクセルだと多くても120回くらいになる。ということで、素直にGDIのクリッピングに任せた方が吉。ってことで終了。ははは

GetTextExtentExPointの続き

で、続きである。みんな同じ事を考えると思うが、ワードラップ以外の目的でもこのGetTextExtentExPointが使えないかな?と思ったのである。例えば、非常に長い文字列をワードラップをせずに描画する場合を考えてみよう(文字数64K超などの)。WindowsのGDIはクリッピング領域外に対する描画は行わないので、何も考えずに、長い文字列をExtTextOutに渡しても、見た目上は問題ない。問題はパフォーマンスなのである。パフォーマンスをとって見るとわかるが、かなり速度に違いがでる。ExtTextOutへの呼び出しは文字列のポインタを渡すので、文字列が巨大であろうとなかろうと、文字列の受け渡しに関するパフォーマンスの違いはほとんど無いことがわかる。

要は、クリッピングに時間がかかってるのである。Windows自体内部でどのようにクリッピングを行っているのかわからないが、文字数64K超の文字列なんて、あきらかにそのほんの一部しか描画されないので、ExtTextOutの呼び出しの前にこのGetTextExtentExPointを使用し、文字列の表示されない部分を切り捨てて、自前でクリッピングを行なおうと思ったのである。

で、いきなり問題につきあたったのである。その問題とは、GetTextExtentExPointの最後の引数であるlpSizeである。これは、GetTextExtentPoint32で取得する文字列の寸法と全く同じものが返されるのであるが、日本語のMSDNによるとNULLを指定できると書いてある。が、実際にはNULLを指定できず、英語のMSDNには、NULLを指定できないと書いてあったのである。つまり、NULLを指定できないって事は、GetTextExtentExPointの呼び出し時に、毎回律儀に文字列全体の寸法を計算しているのである。このAPIをlpnFitの値だけを利用して表示されない部分の切り捨てのために使おうと思っていたので、最後の引数lpSizeにNULLを指定できて、NULLが指定されたとき、lpnFitが求まったら、そこでAPIに処理を打ち切ってもらいたかったのである。

と、今日はいきなり問題につきあたったので、次回に続く。

GetTextExtentExPoint

GetTextExtentExPointである。以前、GetTextExtentPoint32を使ったが、そのEx版である。GetTextExtentPoint32はパラメータとして渡した文字列の幅を返してくれるが、GetTextExtentExPointはMSDNのヘルプにあるように、ワードラップを行うのに便利なのである。具体的に言うと、ある幅をもった領域に長い文字列を描画する時に、その文字列の何文字目までが、文字が途中で切れずに描画できるか求めるのに便利なのである。

例えば、幅100のウィンドウにMSPゴシックのサイズ10のフォントでなにも考えずにExtTextOutで描画すると下の図のようになる。

Expoint1

この場合、「あいうえおかきくけこ」を描画したのだが、「け」の文字が切れてしまっている。そこで、GetTextExtentExPointの出番である。この場合、横幅100の領域に収めたいから、第4引数nMaxExtentに100を指定して呼び第5引数lpnFitの文字数分だけ表示したのが下の図の下の文字列である。

Expoint2

ただ、単純にGetTextExtentExPointで返されたlpnFitの値をExtTextOutの文字数を表す第7引数cbCountに渡しただけである。この場合lpnFitに8が返されていた。もちろん、文字列の幅だけを返すGetTextExtentPointを使えば、どの文字でちょん切れるか計算できないこともない。ただ、GetTextExtentPointを使って求める場合、工夫をしないと何度もGetTextExtentPointを呼び出すはめになるだけだ。

で、次回に続く・・

2007年1月 6日 (土)

Tab文字の展開

文字列にTab文字(U+0009)が含まれている時、何も考えずに、Windows32APIのTextOutやExtTextOutで文字列を描画すると、通常は、Tab文字は使用するフォントのDefaultCharのグリフに置き換えられて描画されてしまう。下のイメージのように。

Exttextouttahoma

DefaultCharというのは、使用するフォントに対応するグリフが無いときに使用される文字である。ちなみに、DefaultCharは、GetTextMetricsで取得できる構造体のtmDefaultCharメンバで取得できる。上の図はフォントにTahoma(DefaultCharはU+001F)、下の図は、MSゴシックを使用したきの図である(DefaultCharはU+FF65)。

Exttextoutgothic

ところで、よくテキストエディタではTab文字を使用して位置揃えを行えるようになっている。そこで、便利なAPIがWindowsに用意されている。TabbedTextOutとGetTabbedTextExtentである。下にこれらのAPIを使って文字列を描画したときのイメージを示す。

Tabbedtextout

どれも、「ABC + Tab文字 + DEFG + Tab文字 + あいうえ」という文字列をTabbedTextOutに渡すパラメータを変えながら、描画したときのイメージである。上から順に、第2引数の描画開始位置のX座標を、それぞれ30、20、0にして渡している。よく、テキストエディタでTab文字を含むテキストを表示したときのイメージと同じように、表示されているのがわかる。ここで、ポイントは、第8引数のnTabOriginである、ここにタブの展開を開始するX座標を指定するのであるが、どの場合も0を指定している。よって、たとえ、第2引数の文字列の描画開始位置のX座標を30、20、0と変えてもタブ展開の開始位置を揃えているので、上のイメージのように、Tab文字の次の文字の位置が揃うのである。このように便利な機能を提供してくれるが、一つ困ったことがある。それは文字列の幅の取得である。

GetTabbedTextExtentで、一見するとTab文字を展開した後の文字列の幅が取得できるのであるが、この引数を見ると、足りないものが一つある。それは、nTabOriginがないのである。すなわち、このAPIはnTabOriginを0とした時の幅しか返さないのである。

上のイメージを見てもわかるように、TabbedTextOutのnTabOriginに渡すパラメータと描画開始位置によって文字列の幅(イメージの先頭文字の「A」の左側から最後の文字「え」の右側まで)が変わるのだ。ちょっと、ありゃありゃと思っていたら、取得する方法があった。それは、なんと

TabbedTextOutの戻り値の下位ワードに幅が返されるのだ。

これを知って喜んだのだが、すぐに、気づいたのが、TabbedTextOutを呼び出すってことは、実際に文字列をデバイスコンテキストに描画しなければならないってことだ。はぁ。

色々書いたが、まぁ、TabbedTextOutを呼び出して幅を求めるのは、Tab文字を展開しないときに使用するGetTextExtentPoint32と比較してそこまでパフォーマンス悪いとは言えないのかもしれない。GetTextExtentPoint32で幅を求めるときも、どの道、GDIのレンダリングエンジンに文字列を渡し、描画イメージを求めなければ、求められないのだから(たぶん)・・・TabbedTextOutで幅だけを求める場合、クリッピング領域外に描画させて求めればとりあえずは問題ないのかもしれない。

補足して、実際はTabbedTextOutWやGetTabbedTextExtentWなどのUnicode版を使用したのが、ANSI版とUnicode版の表記を使い分けるのは面倒なので、ことわりが無い限りUnicode版を指す。それと、Windowsで使用するフォントにグリフが無いときに、そのフォントのDefaultCharのグリフが使われると書いたが、どうも、見てると、複数のグリフが使われてるっぽい。たぶん、これは、フォントリンクの影響だと思う。Windowsでは、フォントのリンクが設定されていれば、たとえ、使用するフォントにグリフがなくても、リンクされたフォントのグリフを探しにいく。で、ここでもグリフがみつからないと、このフォントのDefaultCharのグリフが使われてるのでは?と。

2007年1月 5日 (金)

CharPrevWとCharNextW

WindowsAPIのCharPrevWとCharNextW。どっかで、CharPrevWとCharNextWは合成文字をきちんと処理してくれると記事で読んだ。

で、前にGetFontUnicodeRangesの記事でGetExtentPoint32Wに前に基底文字が存在しない単独の合成文字だけを渡すと0の幅を返すと書いたが、それと同様、前に基底文字が存在しない状態でCharPrevWとCharNextWを呼んでみた。Windows2000ではCharNextWはポインタを次の文字に進めてくれたが、CharPrevWはポインタを前に進めてくれない。ということは、そのような不完全な文字列でCharPrevWを使いループしてると終了条件によっては、無限ループになる。不完全な文字列というのは、外部からデータをファイルなどとして入力すると大いにありえる。ははは。WindowsXPでは、とりあえず、ポインタを進めてくれる。というか、ころころ仕様を変えないでほしい。

サロゲートペアについては、最新のVistaでも、2000とXP同様、サロゲートは2ワードで1文字を表すが、1ワード分しかポインタを進めてくれないらしい。合掌。

2007年1月 4日 (木)

まったりとテスト

まったりとテストしていました。で、Nightly Build(9.0.0.2)をアップロードしました。しばらくは、ちょくちょく最新版を上げますが、ホームページの方では告知しません。最新情報の部分で告知すると、ニュースだらけになるからです。うひゃ。ホームページのダウンロードベージとこのブログの右側のサイドバーだけの更新にとどめたいです。

そういえば、気分を変えたい人のために、隠し機能があります。dbxinsp.iniの[AppConfig]のGUITypeがデフォルトで3になっていますが、これを0~4の範囲で色々変えることによってGUIのスタイルが変わります。

Ultraflat

デフォルトが3のOfficeスタイルですが、上の画像は2のUltraFlatスタイルです。で4がXP上で動かすときに設定する、XPテーマをもちいるスタイルになります。

2007年1月 3日 (水)

DBMS_OUTPUTパッケージ

2007年1月3日版をアップロードした。バージョン番号は0.9.0.0のままだったりするので、開発環境でビルドのたびにビルド番号が自動で更新されるようにしておく。また、前回の記事を見やすいように変更してみた。でも、相変わらずかもしれない・・・

で、OracleのDBMS_OUTPUTパッケージである。おそらく、Oracle開発者にとってもっともおなじみのパッケージである。DBMS_OUTPUT.PUT_LINEやDBMS_OUTPUT.PUTメソッドを使ってサーバー側に確保されるバッファにメッセージを格納するのである。バッファの内容はDBMS_OUTPUT.GET_LINEやDBMS_OUTPUT.GETメソッドで取得できる。主にSQL・PL/SQLの作成時に意図した通りに動いてるかを確認するために、使われる。

SQL*PlUS上で、AUTOTRACE機能同様、手軽にこのパッケージを利用できる。下の画像のように、SET SERVEROUTPUT ONを実行すればよい、これによって、SQL・PL/SQLの実行後、SQL*PLUSが自動で、サーバー上のバッファから、DBMS_OUTPUT.GET_LINEもしくはDBMS_OUTPUT.GETを用いてメッセージを取得、コンソールに表示してくれるのだ。

Sqlplusoutput

で、もちろん、SQL*PLUSと同等の機能がDBXInspectorに備わっている。下の画像のようにSQLエディタ上のアウトプットタブ内のツールバーの「有効にする」を選択し、必要であれば、バッファサイズを変更し実行するだけだ。そうすれば、実行後、バッファの内容が出力される。

Dbxoutput

ちなみに、上の図のように、通常のSQL文の他に、無名PL/SQLブロックもそのまま実行できる。

と、今回は軽めの記事になったが、ブログ書いてるようりも、もっとDBXInspectorをいじくらんといけん!!

DBXInspectorの排他制御

今回はDBXInspector内部で行っている排他制御に関しての話です。といっても、排他制御と言えるほどおおげさなものでもありません。まずは、更新の消失つまりロストアップデートについてです。わかりやすく、下の図のように、SELECT文を発行し、グリッド上でデータを変更するシナリオを考えてみます。

Image1_3 

ここで、選択されているA列が7の行のB列を10に更新しようとして、B列を変更し確定するために、選択行を移動させます。この時、SELECT文を発行してから、編集するまでの間に、他のユーザーによって該当行が変更されている可能性があります。それを知らずに、更新してしまうと大抵は問題なので、つまり、ロストアップデートを防ぐために、選択されたすべての列が変更されていないかチェックします。このようにロストアップデートを防ぎます。よって、

グリッド上で更新する場合、なるべく、多くの列を含めてSELECTして下さい。特に更新された日付を表す列をもっている場合はそれを含めてください。

また、DBXInspectorはデータの変更に注意を払うというスタンスの元で開発されているので、グリッド上でデータを変更し、他の行に移動し確定してもUpdate文は発行されますが、デフォルトでコミットは自動では行われません。よって、トランザクションをコミットする場合は、コミットボタンを押すか、エディタ上でCOMMIT文を入力し、実行ボタンを押してください。言い換えると、

グリッド上でデータを変更したまま、トランザクションをコミットまたはロールバックせずにいると該当行がロックされたままになり、他のユーザーは更新する事はできません

つまり、楽観的ロック(Optimistic Lock)を行います。楽観的ロックとは、更新したい対象の行を照会してもロックはかけず、本当に更新が必要になった段階でその対象行にロックをかけることです。それに対して、悲観的ロック(Perssimistic Lock)とは、更新したい対象行を照会する時点でロックをかけることです。悲観的ロックを用いて、グリッド上などで変更したい場合は、SELECT文にFOR UPDATE句を含めて下さい。

なんか、色々文字を太字にしたり、色変えてるが見にくぃ。

Oracleの接続方法

しばらく、OracleというかDBXInspector周りの話をしようかなと思う。PDFの話はまたいずれかの機会に。と、いっても書く内容は、Web上で検索すれば、ごろごろ出てくるような内容で、目新しいことはない。なぜなら、自分が詳しくないからだ。まずは、Oracleデータベースの接続方法から。プログラムからOracleデータベースに接続する方法として、大体以下のようなものがあげられる。(Windowsからの接続に限定する。)

  1. OCI(Oracle Call Interface)の直接呼出し
  2. ODBC(Open DataBase Connectivity)を用いた接続
  3. OLE DBを用いた接続
  4. ADO(ActiveX Data Objects)を用いた接続
  5. OO4O(Oracle Objects For OLE)を用いた接続
  6. JDBC(Java DataBase Connectivity)を用いた接続
  7. ADO.NETを用いた接続

まず、1のOCIの直接呼出しとは、Oracleデータベースへの接続・SQL文の実行などの機能を提供するライブライリがDLL(oci.dll等)として用意されているので、それを用いて接続を行う方法である。非常に低レベル(機能が貧弱という意味ではない)なAPIなので、習得するのが大変であるが、低レベルである分、非常に細かな制御を行うことができる。

2のODBCインターフェースとは、接続するデータベースによらない共通のインターフェ-スを開発者に提供する目的で開発されたもので、このインターフェースとOracle用のODBCドライバを用いて接続を行う方法である。

3のOLEDBインターフェースは、ODBCと同様の目的で、Microsoft社がOLE DB技術を用いて開発したインターフェースである。Microsoft社はこれをシステムレベルのインターフェースと位置づけているように、実際の業務システムの開発で使うには煩雑である。ODBCと同様、各データベース向けのOLE DBプラバイダと共に用いて接続を行う方法である。従来のODBCドライバを用いて接続できるように、ODBCへの橋渡し(ブリッジ)を行う、例えば、Microsoft OLE DB providers for ODBC driversなどのブリッジドライバもある。

4のADOとは、3のOLE DBの上にかぶさるレイヤー(層)であり、OLE DBに比べて非常にあつかいやすくなっている。.NETではないVisual Basicを用いた開発でよく見かけられる。

5のOO4OはOracleが開発したOracle向けに特化したライブラリでCOM/OLEの技術を用いたライブラリで、ADO同様、Visual Basicを用いた開発でよく見かけられる。OO4Oは内部では、最終的にはOCIを呼んでいる。

6にJDBCであるが、これはJava言語を用いて接続する場合に用いられる。OracleからはJDBC Type2とType 4のドライバが用意されている。

7のADO.NETは.NET Framework向けのデータアクセス技術・ライブラリであり、これも他と同様、各データベース向けのADO.NET プロバイダと共に用いて接続する。ADO同様、ブリッジドライバも存在する。.NETアプリの場合、これが標準方法である。

と、色々書いたが、DBXInspectorは1の方法を用いているので、他のドライバ・プロバイダと称されるものを用いた接続よりオーバーヘッドは少なくなるので、高速かもしれない。しかも、.NET Frameworkを必要としないWin32ネィティブアプリでもある。

って。結論が3行って・・・・・・

DBXInspectorのスクリーンショット

Screenshot_2

2007年1月 1日 (月)

Oracle実行計画

で、ちょっとOracleのお話を。OracleのSQL文を作成する人は、実行するSQL文のパフォーマンスが悪かったりすると、SQL*PlusのAUTOTRACE機能を使って、SQL文の実行計画を確認するものだが、SQL*PlusのAUTOTRACE機能は自分にとっては、表示してほしい情報を表示してくれない。その情報とは、例えば、次のSQL文を考えてみよう。

Sql

二つの表A、Bを共にA列を結合キーに結合して、表BのB列が50000より大の行を返すSQL文である。まぁ、普通はOracleのオプティマイザが適切に処理をしてくれるのだが、SQL*PlusのAUTOTRACE機能の結果からじゃ、B.B > 50000という条件がいつ実行されるのか分からない。つまり、表Aと表Bを結合した後、B.B > 50000の行のみフィルタして返すのか、もしくは、先に表BをB.B > 50000でフィルタした後、表Aと結合するか。この場合、もちろん、表Bを先にフィルタして絞った方が早そうである。つまり、後者の場合だ。で、このSQL文の実行計画をDBXInspectorでとった結果が次の図である。

Plantable

この図のフィルタ述語の列を見れば、一目瞭然、先に表BがB.B > 50000でフィルタされた後、結合されているのがわかる。また、アクセス述語列を見れば、結合条件も分かる。

先ほども書いたが、Oracleのオプティマイザが適切に処理するので、アクセス述語フィルタ述語の情報は見る必要もないかもしれないが、SQL*PlusのAUTOTRACE機能の結果にはこの情報が含まれない。

で、DBXInspectorはどうやって表示してるのかと言うと、なんてことはない、この情報を含む列(access_predicates,filter_predicates)が用意されているので、それを表示してるだけだったり・・・・

ちなみに、SQL*PlusでAUTOTRACE機能を使用するためには、前もって、SYSユーザーでログインし、plustrce.sqlを実行し、PLUSTRACEロールの作成と使用するユーザーへのこのロールの権限付与を行わなければいけない。また、実行計画を格納するPLAN_TABLE表の作成(utlxplan.sql)も。

というか、最後に初めて図を挿入してみたが、適切に表示されることを祈ろう。

DBXInspectorのスクリーンショット

Dbxisc

PDFとDBXInspector

あけおめである。今年は何かいいことがたくさんありそうだ(嘘)。

それでは、PDFである。あらためて言うまでもないほど、メジャーである。自分はパソコンにOSを再インストールするときは、真っ先にAdobeのサイトから最新版のAdobe Readerをダウンロードしてインストールする。で、そのPDF文書とDBXInspectorに何の関係があるのかと言うと、SQL文を作成してる時、SQL文の細かな構文を忘れるというのはありがちなパターンだ。で、大多数の人はOracle社から提供されているマニュアルを見ると思うが、そのマニュアルがPortable Document File形式の文書なのである(今では、HTML形式のマニュアルも用意されているが・・・)。

で、数ヶ月前に思いついたアイデアが、DBXInspectorで、簡単に構文を調べたい関数やSQL文をOracleのPDFマニュアルを使って検索できると便利かな?である。

で、その時、早速実装をしてみたのだが、表示はできたのだが、目的の項目を表示させる方法がわからない。ページ指定はできるのだが、もっと細かな制御の仕方がわからない。で実を言わなくても、Googleで色々調べたが、見つけられなく、実装をあきらめたもしくは保留にしたのである。

で、最近ちょっと、偶然かわからないが、発見したのある。Adobeソフトウェア開発キット(SDK)。これである。英語の資料であるが、ちょっと読んでみたが、Interapplication Communications(IAC)の欄に知りたい事が書いてあった。Named Destination(名前付き宛て先)というのがポイントである。つまり、ページ以外にも、指定の名前付き宛て先に移動できる機能がプログラムからも利用可能なのだ。名前付き宛て先もっとわかりやすく言えば、しおりがOracleのマニュアルで各関数やSQL文毎に設定され、その名称がわかれば、自分の実現したい事がかなう。で、PDFの文書を解析しなければいけないのだが、これはツールを探してきて調べよう。PDFのフォーマットの中身までに手を出すとやけどしそうだ・・・

というか、前置き?が長すぎーーー。

あ、そう、前回のロケールで便利なツールを見つけたのだ。LocaleExplorerである。まだ、β版だが。使いこなせれば開発者にとって便利そう。

« 2006年12月 | トップページ | 2007年6月 »

自作ソフトウェア

無料ブログはココログ

メモ