blog.kotamiyake.me

為せば成る、為さねば成らぬ何事も

mysqldumpの実行がサーバーのリソースを圧迫する問題があって、それを解消するための対応が行われた際に調べたことをまとめておく。

結論

  • --single-transaction オプションと --quick オプションを使う

--single-transaction オプションとは?

  • トランザクション分離モードをREPEATABLE READにする
  • データをダンプする前にSTART TRANSACTION SQLステートメントを発行する
  • InnoDBテーブルのみが一貫した状態でダンプされる
    • MyISAMまたはMEMORYテーブルは状態を変更する可能性がある
  • 有効なダンプファイルを取得するために以下のステートメントを発行してはいけない
    • ALTER TABLE, CREATE TABLE, DROP TABLE, RENAME TABLE, TRUNCATE TABLE
    • 上記のステートメントを使用すると、mysqldump によって実行され、テーブルの内容を取得するSELECTが、正しくない内容を取得したり失敗したりすることがある

--quick オプションとは?

  • テーブルの全レコードをメモリにバッファするのではなく1行ずつダンプする

参考記事

MySQLの文字コードの設定で毎回どうするのがいいのだっけ、と迷ってしまうのでちゃんと調べてみました。

その備忘録として。

開発環境

  • MySQL 8.0.16

結論

文字コードに関しては下記の設定のみあれば良さそう。

[mysqld]
collation-server=utf8mb4_bin

8.0.1以降はそれぞれの文字コードにはutf8mb4がデフォルトで使われているので、特に変更は必要なさそうです。

mysql> show variables like "%char%";
+--------------------------+--------------------------------+
| Variable_name            | Value                          |
+--------------------------+--------------------------------+
| character_set_client     | utf8mb4                        |
| character_set_connection | utf8mb4                        |
| character_set_database   | utf8mb4                        |
| character_set_filesystem | binary                         |
| character_set_results    | utf8mb4                        |
| character_set_server     | utf8mb4                        |
| character_set_system     | utf8                           |
| character_sets_dir       | /usr/share/mysql-8.0/charsets/ |
+--------------------------+--------------------------------+
8 rows in set (0.00 sec)

MySQL :: MySQL 8.0 Reference Manual :: 5.1.8 Server System Variables

資料

既に詳細な情報を記事にしていただいている方がたくさんいるので、そちらを参照していただければよいかと思います。

MySQLの文字コードとCollation – Qiita

utf8mb4のそれぞれのcollationの違いについて解説されています。

MySQL 8.0ではデフォルトで濁点半濁点を区別しなくなる – かみぽわーる

MySQL8.0のデフォルトのcollationがutf8mb4_0900_ai_ciになったことについてのkamipoさんの見解。

 

つい最近とあるアプリの開発中、mysqldump でダンプを取得しようとした際に下記のようなエラーが発生して、ダンプ取得することができませんでした。

$ mysqldump --single-transaction -u root -p -h 127.0.0.1 -P 3307 xxxxxx_development > tmp/development.sql
Enter password: 
mysqldump: Couldn't execute 'SELECT COLUMN_NAME,                       JSON_EXTRACT(HISTOGRAM, '$."number-of-buckets-specified"')                FROM information_schema.COLUMN_STATISTICS                WHERE SCHEMA_NAME = 'xxxxxxx_development' AND TABLE_NAME = 'accounts';': Unknown table 'COLUMN_STATISTICS' in information_schema (1109)

mysqldump のバージョンは8.0を使用しており、MySQL サーバー自体は5.7を利用していました。

$ mysqldump --version
mysqldump  Ver 8.0.13 for osx10.13 on x86_64 (Homebrew)
mysql --version
mysql  Ver 14.14 Distrib 5.7.21, for Linux (x86_64) using  EditLine wrapper

とりあえず解決方法を、ということで調べるとどうやら –column-statistics=0 というオプションを付けると良いということでした。

mysqldumpでCouldn't executeと言われた時の対策 – Qiita

そのとおり実行してみると無事正常にダンプファイルが生成されました。

$ mysqldump --single-transaction -u root -p -h 127.0.0.1 -P 3307 --column-statistics=0 xxxxxx_development > tmp/development.sql

どうやら MySQL が8.0になったときに transactional data dictionary という機能?がサポートされたこと影響しているようです。

恐らく、想定されたシステムテーブルが見つからなくてエラーになっているのではないかと思います。

MySQL 8.0にアップデート!注意すべき点 – Database JUNKY

Upgrading to MySQL 8.0? Here is what you need to know… | MySQL Server Blog

引き続き根本的な原因は調べつつ分かり次第、また記事にしたいと思います!

Dockerを使って好きなバージョンのMySQLで開発を進める方法を紹介したいと思います。

Dockerのインストール

DockerとDocker Composeをインストールして下さい。Macを利用している方は以下のリンクからインストールして下さい。

Docker For Mac | Docker

これでDockerとDocker Composeが利用できるようになります。

docker-compose.ymlの準備

次にdocker-compose.ymlを準備します。

version: '3'

services:
  db:
    image: mysql:5.7
    volumes:
      - db_data:/var/lib/mysql
      - ./docker/mysql:/etc/mysql/conf.d
    ports:
      - "3307:3306"
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: railsdevroot
      MYSQL_USER: railsdev
      MYSQL_PASSWORD: railsdev
volumes:
  db_data:

プロジェクトと紐づくようにRailsのルートフォルダにファイルを作成して下さい。

細かい設定の意味については下記のドキュメントを参考にして下さい。

Compose file version 3 reference | Docker Documentation

volumes:
  - db_data:/var/lib/mysql
  - ./docker/mysql:/etc/mysql/conf.d

MySQLは/etc/mysql/conf.dに*.cnfというファイルが存在するとそちらを設定ファイルとして読み込んでくれるので、個別に設定が必要な場合は独自にファイルを用意してvolumnsセクションでパスを設定します。

今回はDocker用の設定ファイルということで便宜上docker/mysql/というフォルダを作ってそこに設定ファイルを作り読み込むようにしています。

こちらは各プロジェクトに合わせてて適宜読み替えて下さい。

Rails側の設定

あとはRailsのdatabase.ymlで接続先を設定するだけです。

default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  socket: /tmp/mysql.sock

development:
  <<: *default
  database: sample_development
  port: 3307
  password: railsdevroot
  host: 127.0.0.1

気をつける箇所はhostを設定していないとホスト側のDBへ繋ごうとするので忘れずに指定する必要があります。

これで複数のプロジェクトで異なるバージョンのMySQLを使用していても、互いに影響することなく開発を進めることができます。

皆さんもぜひ試して下さい。