9. 価値ある小さきもの達
SQL Anywhereのどのリリースでも、数多くの機能がひっそりと導入されています。これといった喧伝がされないのは、それらの機能が重要であるとだれも思っていないからです。ときには、そのうちの1つが人気を集め、重要性を認められることもあります(例えばUPDATEやINSERTと連携して機能する素晴らしいDEFAULT TIMESTAMPなどがそうです)。筆者は、このような機能を「価値ある小さきもの達」と呼んでいます。次に示すリストの中には、本来ならばトップ10に値する(にもかかわらずその真価がまだ認められていない)機能が1つぐらい潜んでいるかもしれません。
- 関数呼び出しPROPERTY('TCPIPAddresses')は、「自分はいま正しいサーバに接続しているだろうか」という疑問に答えてくれるものであり、サーバがリッスンしているアドレスを192.168.1.51:49270のような形式で返します。
- Ctrlキーを押すことによって、dbisql内のコードのブロックをコメント化したり、コメント化を解除したりできます。
- UPDATEおよびINSERTでDEFAULTキーワードを使用できます(例:UPDATE t SET c = DEFAULT)。
- ENDIFとEND IFを完全に同じものとして使用できます。どちらをIF文と組み合わせて使用し、どちらをIF式と組み合わせて使用すればよいのかを覚える必要がなくなりました。
- dbisqlの"SQL Statements"フレーム内のコードに行番号が表示されます。
- @configurationファイル内でアンパサンド(&)を行継続文字として使用できます。この機能は、High Availabilityおよび組み込みHTTPサーバ用に長いパラメータを設定するときに非常に便利です。
- HTML、SOAP、XML、Raw形式のほかに、JSON、つまりJavaScript Object NotationをWebサービスの結果セットに利用できるようになりました。JSONが我々をXMLから救ってくれるかもしれません。
- 新しいPRIORITYオプションを利用して、アプリケーションのSQL要求が実行される優先レベルを調整できます。例えば、高速のOLTP接続については優先度を「Critical」に設定し、実行時間の長いOLAPクエリについては「Background」(または「Critical」と「Background」の中間にある5つのレベルのいずれか)に設定できます。
- 変数へのUNLOADに関心がない場合でも、LOADとUNLOADのその他の拡張機能の中には気に入るものがあるかもしれません。例えば、暗号化機能、圧縮機能、dbisqでLOADとUNLOADを使用する機能などがあります。あるいは、オプションのトランザクションロギング機能を利用して、ミラーリングされたデータベース環境でLOADとUNLOADを使えるようにするという案はどうでしょうか。
- ミラーリングされたデータベースと言えば、高可用性セットアップのセカンダリサーバに対して読み取り専用クエリを実行できるようになりました。この機能を利用すると、重いOLAPセッションをプライマリOLTPサーバから移動して、セカンダリサーバをフェールオーバー以外の目的にも使うことができます。
- NewPassword接続パラメータを利用すれば、ユーザーは現在のパスワードが期限切れになっている場合でも、新しいパスワードを指定できます。
期限切れのパスワードで思い出したのですが、ログインポリシーの分野では数多くの新機能が追加されています。率直に言って、セキュリティはクールなトピックとは思えないので、これはトップ10のリストに入っていません。しかし、DBAを呼び出さずにログインできる機能には、金に代えられない価値があります。
10. 全文検索
もしもこの記事のテーマが「新機能ベストワン」だったとしても、やはり全文検索を外すわけにはいきません。これはSQL Anywhere 11の一番クールな機能です。全文検索では、複数のLONG VARCHARカラムにまたがる高速検索を実装するために個別のソフトウェアを使用する必要がなく、その検索を実行するためにデータベースの外部にデータを保存する必要もありません。一度でも大きいテーブルに対してSELECT LIKE '%word%クエリを実行したことがある人ならば、「遅い」という言葉の意味が分かるでしょう。そういう人にお勧めなのが全文検索です。
それでは、全文検索の使い方の例をお見せしましょう。この例では、英語バージョンのWikipediaからダウンロードした650万個の項目すべてが含まれたテーブルを使用します。
CREATE TABLE enwiki_entry ( -- 6,552,490 rows, 17.2G total page_number BIGINT NOT NULL, from_line_number BIGINT NOT NULL, to_line_number BIGINT NOT NULL, page_title VARCHAR ( 1000 ) NOT NULL, page_id VARCHAR ( 100 ) NOT NULL, page_text LONG VARCHAR NOT NULL, PRIMARY KEY CLUSTERED ( page_number ) );
最初のステップでは、検索対象となるカラムに対するテキストインデックスを定義します。
CREATE TEXT INDEX tx_page_text ON enwiki_entry ( page_text ) MANUAL REFRESH;
2番目のステップでは、テキストインデックスを構築します。テーブルが非常に大きい場合、この処理には長時間かかることがあります。
REFRESH TEXT INDEX tx_page_text ON enwiki_entry WITH EXCLUSIVE MODE FORCE BUILD;
ただし、いったんインデックスを構築すれば、インデックスを使用するクエリは非常に高速です。次のSELECT文では、新しいCONTAINS句を使って、"Ayn Rand"と完全一致する語句が含まれているすべてのWikipediaの項目を検索します。
SELECT score, enwiki_entry.page_title, LEFT ( enwiki_entry.page_text, 500 ) AS excerpt FROM enwiki_entry CONTAINS ( enwiki_entry.page_text, '"Ayn Rand"' ) ORDER BY score DESC;
CONTAINS句は、enwiki_entry.page_textカラムに対して既に定義されている全文インデックスを使用して、クエリ文字列'"Ayn Rand"'をenwiki_entry.page_textカラムに適用するため、結果セットは一致するローに限定されます。CONTAINS句は、個々のローがクエリ文字列と一致する度合いを測定する暗黙的な"score"カラムも返します。ORDER BY句は、そのカラムを使ってマッチ率の高い順に1位から項目を並べ替えます。図4は、SQL Anywhere 11 Webサービスによって生成された結果をブラウザ画面に表示した様子です。
ここで、筆者が自分の失敗から学んだコツを紹介しておきましょう。CREATE TEXT INDEX文には重要なカラムを忘れずに含めてください。図4を見ると、メインのWikipediaの項目である「Ayn Rand」が1ページ目に表示されていませんが、本当ならこの項目も表示されなければなりません。表示されなかったのは、筆者がインデックスにenwiki_entry.page_titleカラムを含めるのを忘れたからです。全文インデックスが複数のカラムを指定している場合、CONTAINS句は両方のカラムを対象としてスコアを計算します。この例では、タイトルが"Ayn Rand"であるローがクエリ文字列'"Ayn Rand"'に対して非常に高いスコアを獲得するはずです。
全文検索ではたくさんのオプションを利用することができ、筆者がここで説明したのは、ごく基本的なものだけです。もう1つ注意してほしい点があります。2つのカラムに対するインデックスを構築した場合は、CONTAINS句で一方のカラムを参照することができ、そのカラムのみを対象として検索が行われます。これが、筆者の失敗を繰り返してはいけないもう1つの理由です。インデックスに含めるカラムは多ければ多いほどよいと言えます。そうすれば、クエリを設計するときの自由度が高くなります。
ここまで説明をし忘れましたが、Google検索と同様、全文検索の既定のブーリアン演算子はANDです。つまり、クエリ文字列'Ayn Rand'と'Ayn AND Rand'は同じであり、'Ayn OR Rand'にはなりません。