MySQL

提供: MoreslowlyWiki

MySQL 関係の話。

目次

unique index を単なる index にする

しげろ 2008年6月16日 (月) 16:01 (JST)

この件についてどこかにメモを残した気がするけど、忘れてしまったのでここにまた書いた。

参考:

show index from ...で、 Key_name (インデックス名) を確認する。

show index from テーブル名;

そして、alter table テーブル名 drop index ほげほげ とかで修正する。

alter table テーブル名 drop index インデックス名;
alter table テーブル名 add index (カラム名); 


テーブルが壊れたときの症状

テーブルの修復方法 (MySQL本家) も参考になる。

具体的にこんな症状が現れたとき、テーブルが壊れている可能性が高くて、そのときは REPAIR TABLE で直せるときがある。

  • Error: 1062 SQLSTATE: 23000 (ER_DUP_ENTRY)
Message: '%s' は key %d において重複しています
Message: Duplicate entry '%s' for key %d

これ↑見た目には、単なるキーの重複エラーだけど、そのキーで select して0件で、でも insert すると失敗するといった不思議な状態のとき、テーブルのインデックスが壊れている可能性がある。そしたら REPAIR TABLE をためしてみる。

> repair table ほげほげ;
+-----------------+--------+----------+------------------------------------------+
| Table           | Op     | Msg_type | Msg_text                                 |
+-----------------+--------+----------+------------------------------------------+
| なにか.ほげほげ | repair | warning  | Number of rows changed from 2231 to 2232 |
| なにか.ほげほげ | repair | status   | OK                                       |
+-----------------+--------+----------+------------------------------------------+
2 rows in set (0.06 sec)

> repair table ほげほげ;
+-----------------+--------+----------+----------+
| Table           | Op     | Msg_type | Msg_text |
+-----------------+--------+----------+----------+
| なにか.ほげほげ | repair | status   | OK       |
+-----------------+--------+----------+----------+
1 row in set (0.01 sec)


実行時間を制限する

MySQL Forums :: MySQL Query Browser :: Limit execution time? によると、 MySQL で実行時間の制限をかけたいなら、自分で show processlist (MySQL) して pid を調べて kill (MySQL) するしかないみたい。

Python でそんなことをするスクリプトは、この節の下のほうにある。

本当なら、SQL文を見直したり、テーブル設計を工夫したり、パフォーマンスチューニングをしたりして、現実的な実行時間に必ず収まるようにするべきだとおもう。でも、そううまくいかなかったり、絶対に制限時間内にクエリを収めなきゃいけなくて、おさまらなかったら途中で終了させてもいいときとかは、 show processlist; して pid を調べて kill するしかないかもしれない。

それでテーブルが壊れることもある。壊れたら REPAIR TABLE で直す。

import MySQLdb
import dbconf
# ここで dbconf は、ホスト名とかパスワードなどの定数の定義が書かれているモジュールとする

TIMEOUT = 10

class DB:
    def __init__(self):
        self.conn = MySQLdb.connect(host=dbconf.DB_HOST, user='root', passwd=dbconf.DB_ROOT_PASS, \
                                    port=dbconf.DB_PORT, db=dbconf.DB_NAME, unix_socket=dbconf.DB_SOCK)

    def getProcessList(self):
        cursor = self.conn.cursor()
        cursor.execute('SHOW PROCESSLIST')
        r = cursor.fetchall()
        cursor.close()
        return r

    def kill(self, pid):
        cursor = self.conn.cursor()
        cursor.execute('KILL %d' % (pid))
        r = cursor.fetchall()
        cursor.close()
        self.conn.commit()

class DBMonitor:
    def __init__(self):
        self.pidList = []
        self.db = DB()

    def monitor(self):
        for process in self.db.getProcessList():
            pid = process[0]
            user = process[1]
            dbName = process[3]
            command = process[4]
            time = process[5]
            state = process[6]
            sql = process[7]

            # 実行ユーザが hoge で、データベースが foo で、クエリで、
            # TIMEOUT秒以上 statistics とか Locked な状態で、 "SELECT " ではじまってる
            # クエリを kill してしまう!!
            if user == 'hoge' and dbName == 'foo' and command == 'Query' \
               and time > TIMEOUT and (state == 'statistics' or state == 'Locked') \
               and len(sql) > 7 and sql[0:7].lower() == 'select ':
                self.db.kill(pid)

def main():
    mon = DBMonitor()
    while 1:
        mon.monitor()
        time.sleep(TIMEOUT)

if __name__ == '__main__':
    main()


カラムに BINARY 属性がついているかどうか見る

次のようにして show full columns を使う。 MySQL AB :: MySQL 4.1 リファレンスマニュアル :: 4.6.8 SHOW 構文 を参照。

show full columns from table_name ;

具体的にはこうなる。Collation のところが、 BINARY だと utf8_bin となって、そうでないと utf8_general_ci となっている。

> create table testtab ( a varchar(12) binary);
> show full columns from testtab ;
+-------+-------------+-----------+------+-----+---------+-------+---------------------------------+---------+
| Field | Type        | Collation | Null | Key | Default | Extra | Privileges                      | Comment |
+-------+-------------+-----------+------+-----+---------+-------+---------------------------------+---------+
| a     | varchar(12) | utf8_bin  | YES  |     | NULL    |       | select,insert,update,references |         |
+-------+-------------+-----------+------+-----+---------+-------+---------------------------------+---------+

> show full columns from testtab ;
+-------+-------------+-----------------+------+-----+---------+-------+---------------------------------+---------+
| Field | Type        | Collation       | Null | Key | Default | Extra | Privileges                      | Comment |
+-------+-------------+-----------------+------+-----+---------+-------+---------------------------------+---------+
| a     | varchar(12) | utf8_general_ci | YES  |     | NULL    |       | select,insert,update,references |         |
+-------+-------------+-----------------+------+-----+---------+-------+---------------------------------+---------+

CSV 出力

MySQL で CSV 出力してから Python でそれを読み書きする を参考

個人用ツール