GA

2020/05/28

yt-rename-databaseでかつての RENAME DATABASE っぽいことをする

MySQLに RENAME DATABASE が存在していたのは 5.1.7から5.1.22の短い期間だけ(5.1のGAは5.1.30なのでその時にはもう消えていた)

にも拘わらず、かつての日本語版ドキュメントのカバー範囲が「5.1.15-betaまで」なため、俺と似たような時期に日本語ドキュメントを使って勉強していた人はよく知っているイメージ。

ちなみに無くなった理由は「色々考慮してないものが多すぎて色々壊れまくったから」だと思う(個人の見解です)


とはいえごく稀に、「現在のデータベースを他の名前にリネームして切り戻し用にとっておきたい(データだけでも)」ということはあるので、 RENAME DATABASE を模した動きをするスクリプトを作った。

その名も yt-rename-database
Yoku-san no ToolKIT の仲間なので、CentOS 7.xなら releaseごとにrpm を作ってある。
(ただし 0.2.1-0 にはバグがあって yt-rename-database --help ができない…(゚∀。)

$ /usr/local/bin/yt-rename-database --help
..
* --ask-pass, --ask-password, --askpass
  Ask --password by prompt

* --debug
  Set debug output

* --dest=value, --destination=value, --dst=value, --to=value
  Database-name moving to

* --execute
  Execute statements. If --execute is not specified, only print statements.

* --force, -f
  Force RENAME if --to has TRIGGERS, EVENTS, ROUTINES, VIEWS, and Foreign Keys.

* --from=value, --source=value, --src=value
  Database-name moving from

* --help, --usage
  Show this message

* --host=value, -h=value { Default: localhost }
  MySQL host

* --ignore-event, --ignore-events
  Force RENAME if --to has EVENTS.

* --ignore-fk
  Force RENAME if --to has ROUTINES.

* --ignore-routine, --ignore-routines
  Force RENAME if --to has ROUTINES.

* --ignore-trigger, --ignore-triggers
  Force RENAME if --to has TRIGGERS.

* --ignore-view, --ignore-views
  Force RENAME if --to has VIEWS.

* --password=value, -p=value
  Password for the user specified by --user

* --port=value, -P=value
  MySQL port number

* --quiet, --silent, -q, -s
  No output any messages

* --socket=value, -S=value
  Path to mysql.sock
  (this parameter is used when --host=localhost)

* --timeout=value { Default: 1 }
  Seconds before timeout
  (Set into read_timeout, write_timeout, connect_timeout)

* --user=value, -u=value
  MySQL account using for connection and checking
  (need REPLICATION CLIENT, PROCESSLIST and global SELECT priv)

* --verbose, -v
  Verbose output mode

* --version, -V
  Show ytkit version

..

接続関連のオプションは mysql コマンドラインクライアントのものとほぼ一緒。
地味に ytkit で一番気に入ってるのはオプションパーサーで、MySQL公式のクライアント群を模して --socket=/tmp/mysql.sock, --socket /tmp/mysql.sock, -S /tmp/mysql.sock, -S/tmp/mysql.sock が全部ちゃんとパースできる(おまけに公式ではできない -S=/tmp/mysql.sock もできる)

-p の引数が空っぽの時のハンドルは模すのが面倒だったので percona-toolkit や innotopみたいに --askpass オプションがついている(これ、ptとinnotopで確か —ask-passと—askpassと揺れててたまに間違えるので両方とも受け取れるようにしてる)

--from--to が必須オプションになっていて、そいつらを指定しているとこんな風にペロッと「 RENAME TABLE で中身を全部新しいスキーマに移す」ようなSQLスクリプトを吐く。

$ /usr/local/bin/yt-rename-database -uroot -S /usr/mysql/8.0.20/data/mysql.sock --askpass --to=d11 --from=d1
Password:
-- Emulating RENAME DATABASE d1 TO d11
-- I'm dry-run mode. Specify --execute if you wish to execute statements by script.
CREATE DATABASE `d11`;
-- I'm dry-run mode. Specify --execute if you wish to execute statements by script.
RENAME TABLE `d1`.`t1` TO `d11`.`t1`;
-- I'm dry-run mode. Specify --execute if you wish to execute statements by script.
DROP DATABASE `d1`;

もとの RENAME DATABASE 時代にひどい目に遭ったらしいForeignKeyやTrigger, Viewなどがあるとそのままではエラーになる。

$ /usr/local/bin/yt-rename-database -uroot -S /usr/mysql/8.0.20/data/mysql.sock --askpass --from=admintool --to=_admintool
Password:
-- Emulating RENAME DATABASE admintool TO _admintool
admintool has Foreign Keys, not supporting.(For *forcing-execution*, use --ignore-fk or --force) at /home/yoku0825/git/ytkit/bin/../lib/Ytkit/RenameDatabase.pm line 99.

警告を無視する(その辺の不整合はセルフでカバーする)場合のオプションはエラー出力に含まれるようになっている(さっきコミットしたばっか)。

$ /usr/local/bin/yt-rename-database -uroot -S /usr/mysql/8.0.20/data/mysql.sock --askpass --from=admintool --to=_admintool --ignore-fk  --execute
-- Emulating RENAME DATABASE admintool TO _admintool
-- admintool has Foreign Keys, not supporting.(For *forcing-execution*, use --ignore-fk or --force) at /home/yoku0825/git/ytkit/bin/../lib/Ytkit/RenameDatabase.pm line 93.

--execute をつけると実際にスクリプトを実行してリネームする。
あんまり使うこと考えてなくて、 --execute なしでSQLスクリプトとして出力させてぺたこんと貼ればいいんじゃないかなと思っている。

基本的に SHOW TABLESRENAME TABLE を使っているだけなので、ワンライナーでも余裕でいけると思う。

$ mysql -uroot -sse "SHOW TABLES FROM <from_db>" | while read table ; do
>   mysql -uroot -ve "RENAME TABLE <from_db>.$table TO <to_db>.$table"
> done

ふと思ったので作ってみたのでした。

2020/05/18

pt-query-digestでtcpdumpから集約せずに全てのクエリーを取り出す

TL;DR


書き出しが全てなのでそれは置いておいてハマったこと。

  • pt-query-digest --type=tcpdump の2020年問題

  • --output のバリエーションは --help では調べられない

    • man pt-query-digest か、 ドキュメント を見る
    • 俺はパッチ当てようとソースコード泳いでたら気が付いた…
  • サンプル取るのに sysbench を8.0クライアントライブラリにリンクしてコンパイルしたけど、TCP経由の通信はデフォルトでSSL/TLSを使ってた

    • Connector/Cのデフォルトをそのまま使ってた

127.0.0.1:64080 と3306以外のポートを使っているので pt-query-digest --watch-server で指定する必要がある。

$ ./src/sysbench --mysql-ssl=DISABLED --mysql-user=sbtest --mysql-host=127.0.0.1 --mysql-port=64080 oltp_point_select --table_size=100 run

$ sudo tcpdump -s 65535 -x -nn -q -tttt -i any port 64080 | pt-query-digest --type=tcpdump --watch-server=127.0.0.1:64080 --no-report --output=slowlog
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
Reading from STDIN ...
TCP session 127.0.0.1:54906 had errors, will save them in /tmp/pt-query-digest-errors.fAJEZ24
# Time: 200518 19:21:39.084382
# Client: 127.0.0.1:54906
# Thread_id: 4294967296
# Query_time: 0.000168  Lock_time: 0.000000  Rows_sent: 0  Rows_examined: 0
PREPARE SELECT c FROM sbtest1 WHERE id=?;
# Time: 200518 19:21:39.084792
# Client: 127.0.0.1:54906
# Thread_id: 4294967296
# Query_time: 0.000246  Lock_time: 0.000000  Rows_sent: 0  Rows_examined: 0
EXECUTE SELECT c FROM sbtest1 WHERE id=42;
# Time: 200518 19:21:39.084989
# Client: 127.0.0.1:54906
# Thread_id: 4294967296
# Query_time: 0.000121  Lock_time: 0.000000  Rows_sent: 0  Rows_examined: 0
EXECUTE SELECT c FROM sbtest1 WHERE id=46;

うむ。