2009年11月24日火曜日

AmazonRDSでslow queryを出力するようにする方法

AmazonRDSは、デフォルトの設定ではslow queryを出力するようになっていない。
また、MySQLが動いているサーバにアクセスすることができないので、slow queryをログファイルに出力したとしてもそれを閲覧する術がない。
RDSでも採用されているMySQL 5.1からは、slow queryをテーブルに保存できるようになったので、それを使う。

方針

  • ログはテーブル(mysql.slow_log)に出力する。

  • 実行に1秒以上かかったクエリを記録する

  • 100行以上を読み込んだクエリを記録する



普通なら以下のオプションをmy.cnfに設定すればOK。


[mysqld]
slow_query_log = ON
long_query_time = 1.000
log_output = TABLE
min_examined_row_limit=100


RDSの場合は、db-parameter-groupを作成し、パラメータを編集し、db-instanceに適用する。
今回はacme-param-grpというdb-parameter-groupを作成し、acmeというdb-instanceに適用する。

db-parameter-groupを作成

$ rds-create-db-parameter-group acme-param-grp -e MySQL5.1 -d "parameter group for acme"


db-parameter-groupのパラメータを編集
(log_outputはデフォルトでTABLEになっているので設定しない。設定しようとしてもできない)


$ rds-modify-db-parameter-group acme-param-grp \
--parameters="name=slow_query_log, value=ON, method=immediate" \
--parameters="name=long_query_time, value=1, method=immediate" \
--parameters="name=min_examined_row_limit, value=100, method=immediate"


methodに指定できる値はimmediate もしくは pending-reboot

編集したパラメータの確認

$ rds-describe-db-parameters acme-param-grp --source user
DBPARAMETER long_query_time 1 user integer dynamic true
DBPARAMETER min_examined_row_limit 100 user integer dynamic true
DBPARAMETER slow_query_log 1 user boolean dynamic true


sourceに指定できる値はuser 、system、 engine-default

db-parameter-groupをdb-instanceに適用

$ rds-modify-db-instance acme --db-parameter-group-name=acme-param-grp


db-instanceを再起動

$ rds-reboot-db-instance acme


db-instanceにdb-parameter-groupが適用されているか確認

$ rds-describe-db-instances
DBINSTANCE acme 2009-11-04T10:59:28.860Z db.m1.large mysql5.1 100 xxxx available acme.xxxxxxx.us-east-1.rds.amazonaws.com 3306 us-east-1d 1
SECGROUP xxxx active
PARAMGRP acme-param-grp in-sync


PARAMGRPがacme-param-grpになっていて、ステータスがin-syncになっていればOK。

さらにmysqlにアクセスしパラメータが有効になっているか確認する。


mysql > show global variables like 'slow_query_log';
+----------------+-------+
| Variable_name | Value |
+----------------+-------+
| slow_query_log | ON |
+----------------+-------+
1 row in set (0.00 sec)

mysql> show global variables like 'long_query_time';
+-----------------+----------+
| Variable_name | Value |
+-----------------+----------+
| long_query_time | 1.000000 |
+-----------------+----------+
1 row in set (0.00 sec)

mysql> show global variables like 'min_examined_row_limit';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| min_examined_row_limit | 100 |
+------------------------+-------+
1 row in set (0.00 sec)

2009年11月20日金曜日

Python 今日覚えたこと

utf-8な文字列を内部で扱う形式にデコードする際、


unicode_str = utf8_data.decode('utf-8')

とするとutf8_dataにデコードできないバイト列があった場合、UnicodeDecodeErrorの例外をだす。


UnicodeDecodeError: 'utf8' codec can't decode byte 0xb4 in position 1: unexpected code byte


デコードできない文字列を削除してしまっていいのなら'ignore'を引数で渡してやればよい。


unicode_str = utf8_data.decode('utf-8', 'ignore')


さらにdecodeよりunicodeの方が高速らしい。


unicode_str = unicode(utf8_data, "utf-8", 'ignore')


エンコード、デコードの概念はPerlと同じなので理解しやすかった。

参考
http://snippets.hachinos.net/lang/python/user/piro_suke/3/
http://d.hatena.ne.jp/methane/20090816/1250433407

2009年11月18日水曜日

saveをオーバーライドする時はforce_insert、force_updateを渡す

Djangoでdjango.db.Modelsのsaveメソッドをオーバーライドする際


def save(self):


とすると、create()とget_or_create()で以下のようなエラーを吐いた。


TypeError: save() got an unexpected keyword argument 'force_insert'


saveにforce_insert,force_updateを渡すようにしないといけないらしい。
正解はこう


def save(self, force_insert=False, force_update=False):


http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges


create() and get_or_create() will never update existing objects ¶

In [8670] a change was made to both create() and get_or_create() that affects people in two ways:

Firstly, if you have a custom save() method on your model and it is going to be called using create() or get_or_create(), you should make sure you accept the force_insert parameter (best to accept force_update as well, just like django.db.models.base.Model.save()). You don't have to do anything with these parameters, just pass them through to the Model.save() method.

2009年11月17日火曜日

urllib2でgzipされたデータを扱う

ここに書いてあった。
http://diveintomark.org/projects/misc/httpgzip.py.txt

StringIOよりcStringIOのが高速でよいと聞いたのでそちらを使ってみる。
それ以外はまるパクリ。



import urllib2, gzip, cStringIO

def get(uri):
request = urllib2.Request(uri)
request.add_header("Accept-encoding", "gzip")
usock = urllib2.urlopen(request)
data = usock.read()
if usock.headers.get('content-encoding', None) == 'gzip':
data = gzip.GzipFile(fileobj=cStringIO.StringIO(data)).read()
return data

if __name__ == '__main__':
import sys
uri = sys.argv[1:] and sys.argv[1] or 'http://mixi.jp/'
print get(uri)

2009年11月13日金曜日

MySQL 外部キー制約の追加、削除

忘れるのでメモ

MySQL 5.1で確認した。

外部キー制約の確認

SHOW CREATE TABLE テーブル名;


show create table bbs_thread;


外部キー制約の追加

ALTER TABLE テーブル名 ADD FOREIGN KEY (制約を張りたいカラム) REFERENCES 張りたいテーブル(張りたいカラム);


alter table bbs_thread add foreign key (creator_id) references accounts_user(id);



外部キー制約の削除

ALTER TABLE テーブル名 DROP FOREIGN KEY 制約名;


ALTER TABLE bbs_thread drop foreign key creator_id_refs_id_75448b6c;

2009年11月11日水曜日

Leopardでcapistrano

Leopardにはデフォルトでcapistranoが入っているが、バージョンが古いので、更新する

$ sudo gem install capistrano

複数環境にデプロイできるように。capistrano-extをインストールする

$ sudo gem install capistrano-ext