カテゴリー別アーカイブ: LAMP[Linux, Apache, MySQL, PHP]

使用するインデックスを明示する – MySQL インデックスヒントで最適化

 MySQLでクエリをExplainした時にpossible_keysに、IDX_IMPORT, IDX_FSEARCH, IDX_STAT等と複数の候補が存在してkeyにIDX_STATが選択されている時、実際にはIDX_IMPORTの方が高速だったり、他のインデックスよりIDX_STATが低速だったりする時、このインデックスを利用すると高速・低速であるというのをオプティマイザへ知らせる方法としてインデックスヒントがある。

インデックスヒントは

SELECT * FROM estimates USE INDEX(IDX_IMPORT, IDX_FSEARCH) WHERE total>=10000 AND type=1

のように、テーブルに対してUSE/IGNORE/FORCEにより指定する。

USE INDEXはその名の通り指定したインデックスを使用することを推奨するので、インデックス候補中で速い物を指定する。
FORCE INDEXはフルスキャンが非常に重いことを知らせた上で、指定したインデックスを使用することを推奨する。
※特定の条件ではインデックススキャンよりもフルスキャンの方が高速となるパターンがあるので、USEでインデックスを知らせてもそれを使用しないことがあるが、FORCE指定するとフルスキャンを回避してインデックスを使う様になる。 FORCE指定した場合、フルスキャンよりも低速になる可能性もあるので、実データで検証した上で指定した方が良い。
IGNORE INDEXは、逆に使用しないインデックスを指定するので、インデックス候補中で明らかに低速なインデックスがある場合にそれを除外するために使う。

USEとFORCEを比較

EXPLAIN SELECT id FROM estimates USE INDEX (PRIMARY) WHERE type=1 ORDER BY id

possible_keys:NULL key:NULL

EXPLAIN SELECT id FROM estimates FORCE INDEX (PRIMARY) WHERE type=1 ORDER BY id

possible_keys:NULL key:PRIMARY
 ちなみに、ヒントを与えない場合は、possible_keys:NULL key:NULLである。 このクエリを実際に発行すると、USEで0.25秒、FORCEで0.33秒と言うことで、インデックスを使っているけど逆に遅くなった。
 インデックスは何でも張って何でも使えばいいと言う物ではないと言うことだ。
 なお、このようにインデックスを使用すると遅くなる状況でオプティマイザがインデックスを使用するのを防ぐために、USE INDEX ()として、インデックスを使用しないことを明示することも出来る。

(22326)

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

さくらVPSでWindowsを利用していて再インストール無しに上位プランへ移行する

※この記事は古いです。 新しいバージョンの記事を参照してください。

 DTIのServersman@VPSだと、プランのアップグレードは管理画面操作で移行できて、特別な操作は不要だけど、さくらVPSの場合には新しいサーバとして契約して、環境は自分で引っ越し作業をしなければならない。
 Linuxでrsyncを使う方法が公式にあるけど、Windows化している場合には使えないので、独自に移行する方法を考えた。

まず、Windows版DDを入手する。
http://www.chrysocome.net/dd

 ローカルPCにPPTPサーバの設定を行う(Windows7ならば、スタート>コントロールパネル>ネットワークとインターネット>ネットワーク接続を開き、Altキーでメニューを出して、ファイル>新しい着信接続、ユーザを選んで次へ、インターネット接続をチェックして次へ、アクセスを許可をクリックするとPPTPの着信接続が出来る。 ルータでNAPTを使っている場合は、静的ルートでTCPポート1723とGREプロトコル(プロトコル番号47)をPPTPサーバにしたマシンに転送する様にする)
 VPS上のWindowsからPPTPダイアルアップ(新しい接続ウィザード>職場のネットワークへ接続する>仮想プライベートネットワーク接続>IPアドレスにPPTPサーバを設定したマシンのグローバルIPを設定し、それ以外は適当で作成。 このダイアルアップ接続を開いて、PPTPサーバのユーザとパスワードを入力して接続)して、VPSよりサイズの大きいドライブをマウントする。

dd if=\\?\Device\Harddisk0\Partition0 of=z:\sakura_windows.dd

 これで丸コピーしたら、新規導入時と同様、新しいVPSに踏み台Linux経由でdd書き込みしてやれば環境そのまま新サーバに移ることが出来る。 一応、イメージをgzかbz2で圧縮しておいたほうが速いかもしれない。
 ただし、イメージが大きくなっている場合には、踏み台の容量が足りなくなる。
 今回は980円プランから1480円プラン(空きディスクは/dev/sdbの10GBだけ)で足りなかったので、別のサーバにbz2圧縮したイメージを配置して

ssh -l user hoge.piyo “cat ~/sakura_windows.dd.bz2″|bzip2 -dc|dd of=/dev/sda

※userは接続先のユーザ名、hoge.piyoはサーバのアドレス(ヒナギク.com等)である。
みたいに、ssh経由で処理した。
 1980円プランなら/dev/sdbに30GBの空きがあるので、/dev/sdaの20GB全てを放り込んでも余裕がある。

 ちなみに、UNIX系OSで移動する場合には、ssh経由で、

ssh -l user hoge.piyo “dd if=/dev/sda | bzip2 -c”|bzip2 -dc|dd of=/dev/sda

 みたいにして、終始パイプで済ますのもあり。

 これだと、イメージが起動した状態なので、新VPSで起動するときにchkdskをかけてやる必要がある。
 セクタ単位で処理しているから、どこかで致命的なエラーが出るかもしれないが、基本的にはこれで動く。 Acronisのツールなどを入れてシャドウコピー併用でやればもう少し信頼性が上がるかもしれない。

(433)

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

InnoDBを使うと一度増えた容量が減らない – MySQL

 MySQLでストレージエンジンにInnoDBを使うと、レコード削除しても実ファイルサイズが小さくならない。
 これはInnoDBの仕様で、MyISAMだと最適化するとファイルサイズが小さくなるんだけど、InnoDBはファイルサイズが小さくならない。
 なので、変換などの作業用などでInnoDBを使うとファイルサイズが膨らんじゃって、Dropしてもファイルサイズが大きいまんまって事が起きる。
 とりあえず、Dropしてやったときに小さくする方法としては、設定で
innodb_file_per_table=1
を指定してやる。
 通常時、MySQLはInnoDB用に唯一のファイルを作るのだが、それをやめてテーブル毎にファイルを作るようにする指定。
 これを指定すると、テーブルがDropされた時にファイルが消せるので、ディスクの消費を多少抑えられる。

 根本的に、テーブルの一部をDeleteした場合にファイルを小さくするには、テーブルをDumpしてDropしてファイルを削除して、Importすると言う手順が必要になる。
 テーブル毎にファイルが作成されていれば、この作業が楽になるので、Deleteが多く発生することが予想される場合には、先の設定を有効にしておけば、テーブル単位で作業が済むのでメンテナンス時間を短縮できる。

(2302)

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

YouTube埋め込みタグを使用するとIEでnullエラーが発生する

 YouTubeの以前の埋め込みコードを有効にする(Objectタグ方式)で作ったタグをページに埋め込むと、IEでnullエラーが表示されることがある。
 このエラーは、Flash関連で処理されるJavascript(オートロードされるのでScriptタグには書かれていない)でgetElementByName(“”)と処理が行われて、戻り値がNullであるためにエラーが出ている。
 この探索エレメント名は、Objectタグのidが使用されるので、Objectタグにid属性を設定すれば良いのだが、適当な名前をつけると表示されなくなる。
 id属性の値はexternalとすると動画が表示されるようになり、nullエラーも回避される様になる。

(541)

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

テーブルでTDに値が入っていない行を隠す – jQueryパーツ001

条件1 hoge
条件2 piyo
条件3
条件4 piyo
条件5

みたいなテーブルで、右欄が空の場合に行を隠すjQuery。

テーブルのコード

jQueryのコード

サンプル

(388)

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

PHPでデフォルトのSessionを使うとブラウザキャッシュが無効になる

普通にheader関数でCache-Control:max-age=360とかやったけど、ブラウザで見るとno-cacheとか色々設定されていて、Pragma:no-cacheとかも設定されている。
これは、session.cache_limiter設定値がデフォルトでnoneになっているために、Cache-Control, Expires, Pragmaをキャッシュ無効な設定をはき出す様になっている。
部分的にキャッシュを有効化したい場合、PHPマニュアルの関数を使って、設定値をprivateとかにして、適当なsession.cache_expire設定値を入れてやれば良い。
キャッシュさせるパーツにセッションを使わずget渡しにして、session_startしないのもあり。

(365)

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

PHPの謎バグ

PHPでオブジェクトを配列にキャストする場合、Object $objを$array = (array)$objみたいにキャストすると、$obj->propが$array[‘prop’]になるわけだけど、JSONで渡ってきた値をphpのjson_decodeでデコードしたオブジェクトをこのキャストした場合・・・

配列をvar_dumpしたときに

‘1’=>’北海道’
‘2’=>’青森’
…

みたいになるんで、$array[‘1’]にアクセスすると当然’北海道’が戻ってくるべきなんだけど、$array[‘1’]でも$array[1]でもnullが戻ってきてアクセス不能になるという謎現象に陥った。

$temporary = array();
foreach($array as $key=>$val){
$temporary[$key] = $val;
}

みたいな無駄な処理を通すと、$temporary[1]にアクセスすると’北海道’ が得られるようになった。

どうも、PHPの内部処理で型キャストで配列を作る場合に内部構造がおかしくなって、連想配列と数値インデックスの単純配列の動きがおかしくなってしまうようだ。

(277)

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