青柳です。
PostgreSQLのSQLをチューニングするのに役に立つドキュメントは本家のドキュメントです。
ただし、本家のドキュメントは読みにくいところがあるので、用語の解説とわかりやすい説明のリンクをつけました。
本家を読みながらか、先にこちらを読んでから本家を読むとよいです。
あと、実際のチューニング例のリンクも追加しました。
第 14章性能に関するヒント
http://www.postgresql.jp/document/9.2/html/performance-tips.html
■用語
・シーケンシャルスキャン
テーブルを順に走査していく。テーブルの多数を読む場合、インデックススキャンよりも有効。インデックススキャンはインデックス用のデータ領域にアクセスするので余分にアクセスすることになる。例えば本の全てを読むのに一々目次を見ながら読むのは効率的では無いのと一緒。
・インデックススキャン
インデックス用のデータを検査し、本体のテーブルにアクセスする。検索する件数が少ない場合有効。例えば本で目的の章のみ見たい場合、全部読むよりも目次からページを探す方が有効なのと一緒。
・ビットマップインデックススキャン
テーブルの行に対応する位置を0/1で表現して検査する。フラグなど識別する値が少ないと(カーディナリティが低い)有効。
・ネステッドループ結合
2つのテーブルを行単位で逐次比較。
データが小さい場合向いている
・マージ結合
2つのテーブルをソートしておいてから(もしくはBtreeインデックスを使って)結合。
データ量が多い場合向いている
・ハッシュ結合
ハッシュ表を作成しておいてから2つのテーブルを結合
ソートメモリが多い場合向いている
[PostgreSQLウォッチ]第17回 新しい実行プラン・タイプによるPostgreSQL 8.1の性能向上
http://itpro.nikkeibp.co.jp/members/ITPro/oss/20050514/160833/?ST=oss&P=1
ビットマップスキャンについて詳しく説明している
基礎から理解するデータベースのしくみ(9)
http://itpro.nikkeibp.co.jp/article/COLUMN/20060113/227241/
ビットマップスキャンに対する図がわかりやすい
Oracle SQLチューニング講座(3)
SQLチューニングの必須知識を総ざらい(後編)
http://www.atmarkit.co.jp/fdb/rensai/orasql03/orasql03_1.html
結合の図がわかりやすい
■チューニングの例
Linuxトラブルシューティング
第3回 PostgreSQLを遅くしている犯人はどこだ?
http://www.atmarkit.co.jp/flinux/rensai/troubleshoot03/ts03c.html
わかりやすいチューニングの例
20090107 Postgre Sqlチューニング(Sql編)
http://www.slideshare.net/kwappa/20090107-postgre-sqlsql-presentation#btnNext
いささか古い記述があるがわかりやすい
2012年11月29日木曜日
2012年11月9日金曜日
Yiiフレームワークのテーマとレイアウト機能
高瀬です。
YiiはPHPでWebアプリケーションを開発するためのMVCフレームワーク。以下のWebサイトを参照。
初めに: Yii とは何か | The Definitive Guide to Yii | Yii Framework
Yiiでの開発を始めて半年ほどではあるけれども、使おうと思っても触れることができなかった機能に、「テーマ」と「レイアウト」がある。ここではそれらの使い方を考えてみる。
テーマの作成
「テーマ」はWordPressのテーマのように、Webサイトの見栄えを切り替えるために利用する。以下を参照。その他のトピック: テーマ | The Definitive Guide to Yii | Yii Framework
実際に使ってみよう。試しに、Yiiが自動生成する初期プロジェクトの見栄えを変えるテーマを作成してみる。
[初期プロジェクトのテーマ]
[変更後のテーマ]
変更後のテーマには「uniquevision」という名前を付けることとする。まず最初にすることは、ページのレイアウトを決めているファイルmain.phpを、新しく作るテーマ用にコピーすることだ。
(basePath)/protected/views/layouts/main.php
↓
(basePath)/themes/uniquevision/views/layouts/main.php
テーマはthemesというディレクトリ内に作成する。作成したディレクトリの名前がテーマの名前となる。
では、uniquevisionテーマのカスタマイズをしてみよう。コピーしたmain.phpを編集して、ページの左上に表示されている「My Web Application」の表示を、ユニークビジョンのロゴ画像に変更してみる。
ロゴ画像のファイルはテーマごとのディレクトリ内に配置したいので、以下のパスを作成し、保存。その上で、パスをビューに記述する。
(basePath)/themes/uniquevision/images/ti_logo.gif
(変更前) <div id="header"> <div id="logo"><?php echo CHtml::encode(Yii::app()->name); ?></div> </div><!-- header --> ↓ (変更後) <div id="header"> <div id="logo"><img src="<?= $this->themeBaseUrl; ?>images/ti_logo.gif" /></div> </div><!-- header --> |
テーマのディレクトリに配置した画像ファイルのパスを指すには、Yii::app()->theme という変数を利用することができる。テーマのパスを参照しやすいように、Controllerクラスで以下のように変数を定義した。
class Controller extends CController { : public $themeBaseUrl = ''; public function isThemeUsed() { return !is_null(Yii::app()->theme); } public function init() { parent::init(); if ($this->isThemeUsed()) { $this->themeBaseUrl = Yii::app()->theme->baseUrl . DIRECTORY_SEPARATOR; } Yii::app()->clientScript->registerCoreScript('jquery'); } : |
$this->themeBaseUrl という変数を使用して画像ファイルへのパスを作っている($thisはコントローラのインスタンス)。
さて、画像ファイルのパスの切り替え派できたが、CSSはどうするか。これもテーマごとのディレクトリ内に配置したい。とりあえず元のCSSファイルがあるディレクトリをコピーしてしまおう。
(basePath)/css
↓
(basePath)/themes/uniquevision/css
コピー後のCSSファイルを参照するには、やはり$this->themeBaseUrl を使用する。レイアウト用のmain.php内では、元は Yii::app()->request->baseUrl という変数でパスを生成しているので、これを書き換える。
(変更前) <link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->request->baseUrl; ?>/css/main.css" /> ↓ (変更後) <link rel="stylesheet" type="text/css" href="<?= $this->themeBaseUrl; ?>css/main.css" /> |
main.css を編集しておくと、テーマによりデザインが切り替わることが確認できる。
最後に、新しく作成したテーマ uniquevision を有効にする。有効にするには、config/main.phpにテーマの名前を記述する。
(basePath)/protected/config/main.php
最後に、新しく作成したテーマ uniquevision を有効にする。有効にするには、config/main.phpにテーマの名前を記述する。
(basePath)/protected/config/main.php
return array( 'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..', 'name'=>'My Web Application', 'theme'=>'uniquevision', : |
clientScriptの設定によるテーマごとのJavaScriptとCSS
views/layouts/main.php 内に記述されたCSSのファイルパスは前述のようにテーマごとに切り替えることができた。では、clientScriptで指定するJavaScriptやCSSの場合はどうだろうか。例えば、すべてのテーマで共通に「jQuery Alert Dialogs」を使いたいとする。その上で、テーマ個別のJavaScriptも使いたいとする。
config/main.php で、以下のように定義してみた。
(basePath)/protected/config/main.php
return array( : 'components'=>[ : 'clientScript'=>[ 'packages'=> [ 'common' => [ 'baseUrl' => '', 'js' => [ 'js/jquery.alerts.js', 'js/sample.js' ], 'css' => [ 'css/jquery.alerts.css', ], ], 'uniquevision' => [ 'baseUrl' => 'themes/uniquevision/', 'js' => [ 'js/sample_uv.js' ], 'css' => [ ], ], ], ], : |
class Controller extends CController { : public function registerPackage($js = [], $css = []) { $depends = ['common']; if ($this->isThemeUsed()) { $depends []= Yii::app()->theme->name; } Yii::app()->clientScript->packages[Yii::app()->name] = [ 'baseUrl' => '', 'js' => $js, 'css' => $css, 'depends' => $depends ]; Yii::app()->clientScript->registerPackage(Yii::app()->name); } |
このメソッドをアクションから呼び出せば、config/main.phpに記述したJavaScriptとCSSがビューの<head>内に取り込まれる。アクションからの呼び出しは以下のとおり。
class SiteController extends Controller { public function actionIndex() { $this->registerPackage(); $this->render('index'); } |
デフォルトのテーマ用とuniquevisionテーマ用にそれぞれJavaScriptを用意し、jQuery Alert Dialogsでメッセージボックスを表示させるなどすると、どちらのテーマでも動作することを確認することができるだろう。
アクション個別で利用したいJavaScriptやCSSがある場合はどうすればいいだろうか。
上記のControllerクラスに定義したメソッド registerPackage() は、引数で追加のJavaScriptとCSSを指定できるようにしてある。ここに必要なファイルを指定することにする。
public function actionIndex() { $basePath = $this->isThemeUsed() ? 'themes/' . Yii::app()->theme->name . '/' : ''; $js = [ $basePath . 'js/index.js' ]; $css = []; $this->registerPackage($js, $css); $this->render('index'); } |
ここまで、ページのヘッダー/フッター部分やJavaScript、CSSの切り替えをしてきたが、この後はビューの内容をテーマで切り替えてみる。
レイアウトによる段組み
Yiiは初期プロジェクトで2種類の段組みを指定できるようになっている。これはControllerクラスの変数 $layout で指定されている。class Controller extends CController { : public $layout='//layouts/column1'; : public $menu=array(); : |
$layout '//layouts/column2' を指定すると、2列の段組みでページが表示されるようになる。2列の場合、左側の列がメインのコンテンツを表示するエリア、右側の列がサイドバーのエリアになっている。
簡単に2列の段組みにできるのだが、通常、ビューで内容を描画できるのは左側のメインコンテンツ部分だけで、右側のサイドバーには上記Controllerクラスの変数 $menu で指定されるメニュー一覧で固定されてしまっている。任意の内容を表示させたくても、それを引き渡すためのパラメータが用意されていない。さて、どうしたものか。
実験として、初期プロジェクトのテーマでのログイン画面は1列、uniquevision テーマのログイン画面は2列の段組みとしてみよう。uniquevision テーマでは、サイドバー側にログイン用入力フォームを設置する。
ではまず、2列にした場合にサイドバーに描画させる内容をビューに引き渡すパラメータをControllerクラスに用意する。
class Controller extends CController { : public $sidebarParams = null; : |
次に、uniquevision テーマの2列用レイアウトのファイルをコピーする。
(basePath)/protected/views/layouts/column2.php
↓
(basePath)/themes/uniquevision/views/layouts/column2.php
2列の場合、サイドバー側はパーシャルで描画するようにしよう。パーシャルの名前と、それに引き渡すパラメータは $sidebarParams で引き渡す。
(basePath)/themes/uniquevision/views/layouts/column2.php
<?php $this->beginContent('//layouts/main'); ?> <div class="span-19"> <div id="content"> <?php echo $content; ?> </div><!-- content --> </div> <div class="span-5 last"> <div id="sidebar"> <?php $this->renderPartial($this->sidebarParams['partial']); ?> </div><!-- sidebar --> </div> <?php $this->endContent(); ?> |
アクションでは以下のようにする。
class SiteController extends Controller { public function actionLogin() { $model=new LoginForm; : if ($this->isThemeUsed()) { if ('uniquevision' == Yii::app()->theme->name) { $this->layout = '//layouts/column2'; $this->sidebarParams = [ 'partial' => '_login_form', 'model' => $model ]; } } $this->render('login',array('model'=>$model)); } |
テーマが指定されている場合、2列の段組みにして、Controllerクラスの変数 $sidebarParams にパーシャルの名前と、ログイン用入力フォームで使用するモデルをセットしておく。それぞれ、column2.php と、そこから呼び出されるパーシャル(上記の場合は _login_form.php) で参照される。
左側のメインコンテンツはデフォルトのテーマの場合も、uniquevisionテーマの場合も login という名前のビューを描画する。ただし、デフォルトのテーマではメインコンテンツ側(loginビュー)に入力フォームを設置し、uniquevisionテーマではサイドバー側(_login_formパーシャルビュー)に入力フォールを設置。
これで、段組みが1列の場合でも2列の場合でもログイン用入力フォームを動作させることができた。
なお、layouts/column1.php は uniquevision テーマにコピーしていないが、ログイン画面以外の画面が初期プロジェクトと同様に1列の段組みで表示される。つまり、レイアウトやビューのファイルがテーマに定義されていない場合は、デフォルトのテーマ(protected/views以下のファイル)が使用され、差分となるファイルだけをテーマに定義すればよいことが分かる。
おわり
テーマもレイアウトもWebページの見栄えを制御するものだが、うまく使えば見栄えを切り替えるための分岐処理などは書かなくてもよくなりそうだ。しかし、テーマごとに同じ内容のソースファイルを設置してしまうとメンテナンス性がよくないので、どのように利用するかはプロジェクトごとに検討する必要がある。ちょうどこの記事を書いている時に、あるプロジェクトで本番環境、ステージング環境、開発環境で画面の背景色を切り替えたい、という要件があり、一部テーマを利用した。活用できるケースは意外に多いのかもしれない。
2012年8月29日水曜日
MongoDBのAggregationフレームワークの紹介
青柳です。
そろそろリリースされるMongoDB2.2で利用できるAggregationフレームワークについて紹介します。
例としてTwiiterAPIのHomeの結果をコレクションとして保存します。
具体的には以下のリンク先を参考にしてください。
https://dev.twitter.com/docs/api/1/get/statuses/home_timeline
・Count
コレクションやクエリーにマッチするオブジェクトの数を返します。
> db.tweet.count();
> db.tweet.count({user.screen_name: "aoyagikouhei"});
indexがあると早くなります。
> db.tweet.ensureIndex({user.screen_name: 1});
・Distinct
指定したキーに対してコレクションの個別のリストを返します。
>db.tweet.distinct("user.screen_name");
["aoyagikouhei", "masason"]
クエリーもオプションでつけられます。
> db.tweet.distinct("user.screen_name", {id : {$gte : 1234567}});
Distinctは単体のBSONを返すので最大ドキュメントサイズ(4MB/16MB)を超える場合はMapReduceを使います。
・Group
SQLのgroup byと同じような、要素をグループ化した配列を返します。
例えば、IDが1234567以降で各ユーザがつぶやいた数の集計は以下のようになります。
> db.tweet.group({
key : {"user.screen_name" : true},
cond : {id : {$gte : 1234567}},
initial : {count : 0},
reduce : function(obj, prev) {prev.count++;}
});
Groupも単体のBSONで返すので結果が大きい場合はMapReduceを使います。
また、複雑な集計の場合もGroupでは限界があるので、MapReduceを使います。
そろそろリリースされるMongoDB2.2で利用できるAggregationフレームワークについて紹介します。
例としてTwiiterAPIのHomeの結果をコレクションとして保存します。
具体的には以下のリンク先を参考にしてください。
https://dev.twitter.com/docs/api/1/get/statuses/home_timeline
・Count
コレクションやクエリーにマッチするオブジェクトの数を返します。
> db.tweet.count();
> db.tweet.count({user.screen_name: "aoyagikouhei"});
indexがあると早くなります。
> db.tweet.ensureIndex({user.screen_name: 1});
・Distinct
指定したキーに対してコレクションの個別のリストを返します。
>db.tweet.distinct("user.screen_name");
["aoyagikouhei", "masason"]
クエリーもオプションでつけられます。
> db.tweet.distinct("user.screen_name", {id : {$gte : 1234567}});
Distinctは単体のBSONを返すので最大ドキュメントサイズ(4MB/16MB)を超える場合はMapReduceを使います。
・Group
SQLのgroup byと同じような、要素をグループ化した配列を返します。
例えば、IDが1234567以降で各ユーザがつぶやいた数の集計は以下のようになります。
> db.tweet.group({
key : {"user.screen_name" : true},
cond : {id : {$gte : 1234567}},
initial : {count : 0},
reduce : function(obj, prev) {prev.count++;}
});
Groupも単体のBSONで返すので結果が大きい場合はMapReduceを使います。
また、複雑な集計の場合もGroupでは限界があるので、MapReduceを使います。
2012年8月23日木曜日
Webサイト設計で利用したいツール
高瀬です。
ここ最近で個人的に仕事上で気になった、以下の3つの言葉について書いておく。
ここ最近で個人的に仕事上で気になった、以下の3つの言葉について書いておく。
- マークアップエンジニア
- ワイヤーフレーム
- コンセプトダイアグラム
マークアップエンジニア
第1回 マークアップ・エンジニアって何?
マークアップエンジニアのキャリアパス
フロントエンドエンジニアを探す方法5つ
-----
フロントエンドエンジニアとはバックエンドエンジニアと対比して説明される職種で、ここでは、HTMLやJavaScript、CSSといったクライアントサイドの技術を中心に扱う、いわゆるWebアプリケーション部分を担当する人々と考えていただいて問題ないかと思われます。
-----
フロントエンドエンジニア(マークアップエンジニア)とコーダーの違い
サーバ側の開発を行うエンジニアに対比させた呼び方ということであれば、フロントエンドエンジニアとマークアップエンジニアの仕事に大きな違いはないのかもしれない。
ワイヤーフレーム
先日、同じプロジェクトを担当しているメンバーに、「画面のワイヤーですでに作っているものがあれば参考にしたいので見せてほしい」とお願いしたところ、色付き、影付き、写真付きの画面図案を出してくれた。現場のワークフローで覚える Webサイト制作教室
サイトマップ | Webサイト全体の構造を表す図。登場するページとそのつながりを示す。 |
ワイヤーフレーム | サイトマップに、各ページや導線の詳細を記述したもの。Webサイトの設計図。 |
ページレイアウトのワイヤーフレーム | ページの構成要素と配置を記述した図。 |
デザインモックアップ | ページのデザインを決定するために、ページを画像として作成したもの。 |
この定義に当てはめると、自分の認識していた「ワイヤーフレーム」とは「ページレイアウトのワイヤーフレーム」で、見せてもらったのは「デザインモックアップ」に近い内容、ということになりそうだ。
- ワイヤーフレームは、Webページの構成要素を洗い出すとともに、実際に表示するサイズで配置を決定するために作成する図。
概要 | 社内で各メンバーが読んだ書籍を紹介するサイト。書籍のタイトルや感想を投稿すると、それに対して他のメンバーがコメントを記入する。 |
目的 | 書籍の情報を共有することで、社内での技術書の利用と自己啓発を促す。 |
サイト名は、適当に「UV Shelf」とでもしておこう。以下の流れで進める。
- サイトマップ(サイト構成のみ)を作成する
- サイトマップ(各ページの詳細含む)を作成する
- 各ページのワイヤーフレームを作成する
社内で利用することを想定しているのでユーザ認証なんてどうでもいいが、投稿やコメントをする際にあらかじめユーザ名がわかっている方がいいように思うので、一応ログイン画面などを付けてみた。
次にサイトマップの詳細。管理画面とユーザ登録画面の導線がサイトマップと違ってしまったが、これはサイトマップを直す方向で考えることにする。
最後にTOP画面のワイヤーフレーム。
TOP画面には書籍の一覧と、ログイン(ログアウト)、書籍の投稿、管理画面へのボタンまたはリンクを配置。これでサイトマップ詳細に記述した画面の構成要素を満たす。
また、横幅はスクロールバーを含めて920px、スクロールバーを除くと900pxとなるようにしている。これで実際のWebページ表示のサイズを表現する。適当に描いたのでマージンなどはバラバラなのだが、きっちり作りこめばデザインモックアップに利用できるようになるはず。
と、ここまで書いて、そういえばページングの機能が抜けているなぁとか、パスワード変更をする画面がないなぁとか、いろいろ気づくことがある。まだまだ仕様が詰め切れていないようだ。
ちなみにこの図はCacooで作成している。
ワイヤーフレームを作成するツールは他にも以下のようなものがある。
Webクリエイターボックス(2010年)
Webサイトの骨組み: ワイヤーフレームを素早く・手軽に・美しく制作する
コンセプトダイアグラム
Webサイトをリニューアルする案件において、現行サイトの整理をするために「コンセプトダイアグラム」を作ってみた、というメンバーがいる。少し調べて見ると、Webサイトのアクセス解析などで利用されているらしい。立ち寄った本屋では以下の本に4ページだけ記載されているのを発見した。
murak.net(2012年)
『入門ウェブ分析論[増補改訂版]』レビュー
以下、その本の内容である。コンセプトダイアグラムの前に、Webサイトを分析するうえで覚えておかなければならない用語がある。
用語 | 意味 |
KGI | Key Goal Indicator:経営目標達成指標。サイトの目的、目標。目標は数値を含めて設定する。 |
CSF | Critical Success Foctor:重要成功要因。KGIに決定的な影響を与える要素。 |
KPI | Key Performance Indicator:業務評価指標。CSFの具体的な施策と目標設定。 |
それぞれ、いくつか例が記載されている。以下、分析対象のサイトをメディアサイト、広告型サイトとした場合の例。
指標 | 指標例 |
KGI | 利用者を800万人に増やし、月間1000万円の広告収入を得る |
CSF | ・閲覧数を増やす ・滞在時間を増やす ・ブランド名を理解してもらう |
KPI | ・新規ユーザのページビュー数を1.5倍にする ・新規ユーザの訪問数を月間500万から800万に増やす ・サイト名(ブランド名)での検索回数を1.5倍に増やす ・1訪問あたりの滞在時間を1.5倍に増やす ・1訪問あたりの平均ページビュー数を10から12に増やす ・広告掲載ページのページビュー数を現在の2倍に増やす ・広告枠を現在の1.5倍に増やす |
KGIやKPIの指標を設定するためには、対象サイトの目的やユーザ像を理解しておく必要がある。サイトを整理し、理解するために、コンセプトダイアグラムを作成する、という手法がある。
「入門 ウェブ分析論」の内容抜粋は以上。というわけで、コンセプトダイアグラムは、Webサイトの利用者が閲覧している、主要なコンテンツと導線を図に描き、どのようなKPIを設定するのがよいかを検討するための図、といえる。
実例が以下のサイトで紹介されている。
Web担当者Forum(2011年)
アクセス解析新手法「コンセプトダイアグラム」とは? サイトの全体像を可視化して知るべき指標を知る【レポート】
また、コンセプトダイアログによるWeb改善フレームワークを提唱されている清水 誠氏のスライドが以下のサイトに掲載されている。
Six Apart ブログSix Apart ブログ(2012年)
おわり
「技術ブログ」ということで、もっと実装寄りの内容が期待されていると分かってはいるのだけれども、現在取りかかっている案件の作業フェーズの都合上、今回はずいぶんと設計よりな話になってしまった。
このブログにおいて自分が担当するテーマは「マークアップエンジニア」ということになっているが、テーマを決める際に「Web関連」などと曖昧なことを言ってしまったためにそうなったのであって、果たしてそれに向かっていけるかどうか不安ではある。
マークアップにたどり着くのはまだまだ先になりそうな気はしているが、一応次回以降も自分担当の回はそれっぽい方向で。
このブログにおいて自分が担当するテーマは「マークアップエンジニア」ということになっているが、テーマを決める際に「Web関連」などと曖昧なことを言ってしまったためにそうなったのであって、果たしてそれに向かっていけるかどうか不安ではある。
マークアップにたどり着くのはまだまだ先になりそうな気はしているが、一応次回以降も自分担当の回はそれっぽい方向で。
登録:
投稿 (Atom)