月別アーカイブ: 3月 2011

MySQL – インデックスが働かない / Zend Framework

MySQLで

stock
id:int name:varchar num:int

みたいなテーブルに

SELECT * FROM stock WHERE num=’1′

みたいなクエリを投げる。
厳密に言えば、numはint型で、クォーテーションでくくったものは文字列型であるから、数値=文字列の比較は常に成立しないのだけど、MySQLは気を利かせてnum=1を検索して返してくれる。
しかし、このとき、インデックスは動作しない。 型をミスってSQL文を埋め込んでいても勝手に変換して動作するくせに、インデックスが働かずボトルネックになるというアレな状態だ。
適当な感じのインデックスが張ってあるのに、EXPLAINしてやると使用キーが無かったりするのはこんな原因だったりする。
普通にSQLを自分で構築している場合には、コードを修正してクォーテーションを外せば良い。

この問題は、表題のZend Frameworkにもあって、自動エスケープモードを有効にしていると、型に関係なく勝手にクォーテーションでくくられてしまう。 ZendFrameworkのDB機能ではSELECT * FROM stock WHERE num=:numみたいなSQL文とarray(‘num’=>1)の様なパラメータを渡してやるわけだけど、自動エスケープモードで発行するとSELECT * FROM stock WHERE num=’1′になってしまうので、インデックスが働かない状態になる。
このような場合、DBインスタンスを作るときに自動エスケープを無効化して、必要なパラメータを手動でエスケープしなければならない。 また、自動エスケープ処理部分で、is_string($var)の場合だけクォーテーションをかけるようにフレームワーク側を修正する手もある(面倒な場合、DB定義をALTER TABLE stock CHANGE num num VARCHAR(11)のようにして文字列型にしてしまう手もある)

(70)


カテゴリー: MySQL | コメントをどうぞ

ServersMan@VPS – Apache自動リロード / ioncube loader

ServersMan@VPSの初期設定だと、cron.dailyが午前3時に走って、その中のlogrotateからApacheがリロードされる。
証明書の差し替え予定があったんだけど証明書自体が届いてなかったから、設定ファイルをとりあえず書き換えてApacheをリブートするときに証明書があれば良いだろうと思っていたら、自動リロードでこけてApacheが落ちてて焦った。

そういえば、使ってなかったzend extensionで、ioncube loader(ioncube製PHPコンパイラを通したコードのロード用モジュール)ってのがあるんだけど、デフォルトでモジュールが入ってるけどPHP5.1用なのでPHP5.3にするとApache起動時にエラーが出るんで、対応。

#wget http://downloads2.ioncube.com/loader_downloads/ioncube_loaders_lin_x86.tar.gz
#tar xzf ioncube_loaders_lin_x86.tar.gz
#cd ioncube
#mv ioncube_loader_lin_5.3.so /home/solarspeed/ioncube/
#vi /etc/php.d/ioncube.ini
zend_extension = /home/solarspeed/ioncube/ioncube_loader_lin_5.1.so

zend_extension = /home/solarspeed/ioncube/ioncube_loader_lin_5.3.so

#/etc/init.d/httpd restart

これで、Apache起動時のエラーが消えてスッキリ。

(177)


カテゴリー: LAMP[Linux, Apache, MySQL, PHP] | コメントをどうぞ

RTX1000設定 – sshが切れる/NATテーブル溢れ

 前から気になっていたことなんだけど、RTX1000ルータでマスカレード使用時にsshが切れる。 使用中でも切れる。 サーバとクライアントに10秒KeepAlive設定をしても切れる。
 大体、ローカルサーバに入りっぱなしなので、サーバネットワーク側ルータを通って外部に繋いでいるので特に問題なかったのだが、ちょっと調べてみたら、コマンドレファレンスに

nat descriptor masquerade rlogin ディスクリプタ番号 on/off

って言う設定項目があって、これのデフォルト値はoffなんだけど、マスカレード環境でsshやscpを使う場合にはこれをonにするよう書いてあった。
てことで、nat descriptor masquerade rlogin 1 onと書いてやったが、やっぱり切れる。
 んー、Wiresharkとかで通信を覗かないとダメかなぁ。

 後は、NATテーブルがあふれる症状。 デフォルトでマスカレードのTTLが900秒もあるので、Linuxとかのイメージを落とすときにtorrentを立ち上げたりすると、NATデーブルがぐっちゃぐちゃになって落ちる(RTX1000では、NATテーブルは1000件しか保持できないので、FINパケットをしっかりと送ってくれないホストと通信していると結構簡単に溢れる)

nat descriptor timer ディスクリプタ番号 秒数

この設定を使ってnat descriptor timer 1 300とバッサリ短縮してやったが、torrentの接続試行数が多く、まだ重めなので、プロトコル・ポートオプションを指定して、nat descriptor timer 1 protocol=tcp port=10080 60の設定を入れて、torrentの受け入れポートTCP:10080のTTLを60秒に切り詰めたらCPU負荷50%程度で落ち着くようになった。

(795)


カテゴリー: LAMP[Linux, Apache, MySQL, PHP] | コメントをどうぞ

SSL設定 – 関連コマンド

SSL証明書を取得するのに、作ったCSR(証明書要求)の中身が間違っていないか確認したい場合。

openssl req -in /etc/pki/tls/certs/hoge.csr -text

これで、CSR作成時に入力した内容が表示される

受け取った証明書の中身を確認する場合は

openssl x509 -in /etc/pki/tls/certs/hoge.crt -text

一般的にこれで表示できる。 先のコマンドは、タイプにreq(csREQuest)を指定していて、今回はx509(X509証明書)を指定している。 別の形式の証明書が送られている場合は、そのタイプにあわせる。

(27)


カテゴリー: サーバ設定 | コメントをどうぞ

MySQL de ビュー

 DBMSのビュー機能って言うのは、簡単にいえばSELECT文でテーブルの複製のようなものを構築する機能。

例えば、
orderテーブル

id
item_id
unit

itemテーブル

id
name
price

みたいなテーブルがあって、ビューを

CREATE VIEW order_view AS SELECT order.id, name, unit*price as total_price FROM order, item WHERE order.item_id = item.id

の様に定義しておくと、id, name, total_priceを持つビューができる。
 ビューはテーブル同様、 SELECT * FROM order_view の様に処理できる。

 CREATE TABLE ~ SELECT ~形式でテーブルを作ると似た結果になるが、CREATE TABLE ~ SELECT ~では、CREATE TABLEしたタイミングの情報がテーブルに保持されるのに対して、ビューはビューに対してクエリが投げられる度に、AS~の文を実行してデータを取得する。
 よく使う取得形式について、SELECT *で済ませる様に定義したり、制限ユーザにテーブル全項目ではなくカラムを限定してビューとして提供したり、内部構造の変更を吸収するレイヤーとして使うことができる。

 便利に思えるビューではあるが、色々と制限もある。
 例えば更新系クエリ(INSERTUPDATE)は、レコードが一意に元テーブルのレコード・カラムを特定できる事が最低条件である。
 先に示した定義の場合、total_priceunitpriceの演算により求められるカラムであり、total_priceが元テーブルにどのような値を与えるか不定であるから更新できない。
手の込んだ構造のビューは基本的に更新できない、見る(view)ためだけの物であると考えたほうが良い。
 また、ビューにはインデックスを設定することもできない(クエリを投げた段階でSELECTしてデータを取得するので、SELECT後にインデックスを構築して検索したとしても、コストが増えるだけ)ため、パフォーマンス的に弱いし、集計操作などにも癖がある。
 パフォーマンス制限について、一回の接続で繰り返し同じビューを利用するなら、ビューではなく、一時テーブル(CREATE TEMPORARY TABLE ~)を接続するたびに構築した方が高速な事もある(接続中はマスタの変更は反映されないし、更新系は結局、元テーブルに投げなければならないが)

(24)


カテゴリー: LAMP[Linux, Apache, MySQL, PHP], MySQL | コメントをどうぞ

PHP チューニングの基本

MySQLの時にも書いたけど、チューニング情報収集が大事(どこでどれだけ時間がかかっているか知る)
Webシステムでは、どのページがどれくらい時間がかかっているかというのを知った上で、そのページの中のどこが時間がかかっているかを調べる。

で、各ページの処理時間を簡単に表示するのに、
php.ini

auto_prepend_file
auto_apend_file

この設定を使うと便利。

これは、PHPのページアクセス時に、スクリプトに先立って自動実行されるファイルと、終了時に自動実行されるファイルを指定するものだ(exit命令で終了すると自動実行されない)
この設定は.htaccessでも設定できるので、開発ディレクトリに
.htaccess

php_value auto_prepend_file autoprepend.php
php_value auto_append_file autoappend.php

のように設定して、
autoprepend.php

<?php $time_start = microtime(true); ?>

autoappend.php

<?php echo(‘runtime:’.(microtime(true)-$time_start).’sec’); ?>

みたいなファイルを用意しておくと、ページの最後にruntime:4.6920776367188372secとか表示されるので、これが大きいページから処理していくと効率が良い。

なお、この自動実行ファイルはrequiredなので、ファイルがないとFatalErrorで落ちるので、include_pathに置いておくのが良い。

(60)


カテゴリー: LAMP[Linux, Apache, MySQL, PHP], PHP | コメントをどうぞ

PHP de オブジェクト指向 Part.2

PHP de オブジェクト指向part.2

この間のクラスに機能を追加してみる。

class SimpleDataObject
追記・変更

protected $_mask;

public function __construct($id){
$_mask[] = ‘id’;
foreach(get_object_vars($this) as $key => $val){
if(strpos($key, ‘_’)===0) $this->_mask[] = $key;
}
$this->id = $id;
}

public function getColumns(){
$ret = array();
foreach(get_object_vars($this) as $key => $val){
if(in_array($key, $this->_mask)) continue;
$ret[] = $key;
}
return $ret;
}

public function setByArray($array){
foreach($array as $key => $val){
try{
$this->set($key, $val);
}catch(Exception $e){
throw new Exception(‘[‘.__FUNCTION__.’]エラー:’.$e->getMessage());
}
}
return true;
}

で、前回作ったEstimateDataObjectを使って

$obj = new EstimateDataObject(1);
$cols = $obj->getColumns();
$sql = ‘SELECT ‘.implode(‘,’, $cols).’ FROM Estimates WHERE id=’.$obj->get(‘id’).’;’;
$res = mysql_query($sql);
$row = mysql_fetch_assoc($res);
$obj->setByArray($row);

こんな事をすると、EstimateDataObjectで定義した変数を列挙したSQL文を作って$objに読み込むことが出来る。
で、これを更新保存するには、

$obj->set(‘name’, $_GET[‘name’]);
$sql = ‘UPDATE Estimates SET’;
foreach($cols as $col){
$sql .= ‘ '.$col.'=’.$obj->get($col).’,’;
}
$sql = rtrim($sql, ‘,’);
$sql .= ‘ WHERE id=’.$obj->get(‘id’);
mysql_query($sql);

みたいなことで出来る。
EstimateDataObjectだけでなく、SimpleDataObjectを継承してプロパティを増やしたクラスもこのコードで対応できたりする。
便利便利

(9)


カテゴリー: LAMP[Linux, Apache, MySQL, PHP], PHP | コメントをどうぞ