20200818のMySQLに関する記事は8件です。

nginx image に mysql を入れる際の注意点

対象

docker 環境で nginx の公式image に mysql クライアントをインストールする際に詰まった人 :rolling_eyes:

調査&解決

上記のリンクから確認できるが、 公式image は FROM debian:buster-slim を使っている。
ベースイメージが debianであることがわかったので https://hub.docker.com/_/debian を見ると
buster-slim は debian 10系で有ることがわかった。

buster系では mysql-clientが存在しないので default-mysql-server を使用してinstallする

$ sudo apt-get update
$ sudo apt-get install default-mysql-server

これで入る。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【備忘】Docker Container の MySQL Server にアクセスする方法メモ

Dockerコンテナ上に立てたMySQL Server にアクセスする際に意外と手間取ったのでメモ。

前提

OS: macOS 10.14.6
docker desktop: v2.3.0.3
Dockerイメージ: https://hub.docker.com/r/mysql/mysql-server

手順

コンテナ起動してアクセス。ポートマッピングを忘れない!

$ docker run --name=mysql-develop \
             -p 3306:3306 \
             -d \
             mysql/mysql-server
$ docker exec -it mysql-develop bash

設定ファイル(/etc/my.cnf)に以下を追記。
docker run で起動している場合、ホストのIPは127.10.0.1です。

my.cnf
bind-address = 127.10.0.1

ルートユーザでコンテナ内からサーバーにアクセス。
パスワードはコンテナ作成時に自動でせいせされるので、ログから確認する。

$ docker logs mysql-develop 2>&1 | grep GENERATED
[Entrypoint] GENERATED ROOT PASSWORD: XXXXXXXX
$ docker exec -it mysql-develop mysql -u root -p
Enter password: # XXXXXXXX

リモートアクセス用のユーザー作成、権限付与。

CREATE USER 'myuser'@'localhost' IDENTIFIED BY 'mypass';
CREATE USER 'myuser'@'%' IDENTIFIED BY 'mypass';
GRANT ALL ON *.* TO 'myuser'@'localhost';
GRANT ALL ON *.* TO 'myuser'@'%';
flush privileges;

コンテナから抜けて、ホストのクライアントからアクセス。

$ mysql -u remote_user -h '127.0.0.1' -p
Enter password: # mypass入力

参考

https://stackoverflow.com/questions/16287559/mysql-adding-user-for-remote-access

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MySQL⑧ データの集計処理、サブクエリ

users_with_team テーブル

id name score team
1 AAA 11 team-A
2 BBB 22 team-B
3 CCC 33 team-C
4 DDD 44 team-B

データの個数を調べる count()

select count() from users_with_team;
➡️4

特定のカラムのデータの個数を調べる count(カラム名)

select count(score) from users_with_team;
➡️4

sum で合計、 min で最小値、 max で最大値、 avg で平均

select sum(カラム名) from users_with_team; ➡️110
select min(カラム名) from users_with_team; ➡️11
select max(カラム名) from users_with_team; ➡️44
select avg(カラム名) from users_with_team; ➡️27.5

重複したレコードを取り除いて取得する distinct カラム名

select distinct team from users_with_team;

team
team-A
team-B
team-C

重複したレコードの数を数える

select count(distinct team) from users_with_team;
➡️3

グループ化する

グループごとの合計をだす group by グループ化の基準にするカラム名

select sum(score), team from users_with_team group by team;

逆順にする desc

select sum(score), team from users_with_team group by team desc;

グループ化の後に条件をつける group by グループ化の基準にするカラム名 having 条件

havingでは、グループ化したカラム、集計した値以外使えない
select sum(score), team from users_with_team group by team having sum(score) > 10.0;

特定の条件でグループ化する where 条件 group by グループ化の基準にするカラム名

where で条件付きで抽出した後にグループ化する
select sum(score), team from users_with_team where id > 3 group by team;

一時的に使用するテーブル サブクエリ

元のテーブル

id name score
1 AAA 11
2 BBB 22
3 CCC 33
4 DDD 44

ここから集計の為のテーブルを一時的に作成する

select sum(t.score), t.team from(
  select       ⬅️ここから
    id,
    name,
    score,
    case
      when score > 8.0 then 'Team-A'
      when score > 6.0 then 'Team-B'
      else 'Team-C'
    end as team
  from users) as t   ⬅️ここまでがサブクエリ
group by t.team;

サブクエリを使用しないと users_with_teamテーブルを作成してから集計する

create table users_with_team
select id, name, score,
    case
      when score > 8.0 then 'Team-A'
      when score > 6.0 then 'Team-B'
      else 'Team-C'
    end as team
from users 

select sum(score), team from users_with_team group by team;

抽出条件を保存する view

viewはテーブルの様に扱われる

viewを作成する create view ビュー名 as 抽出条件

create view top3 as select * from users order by score desc limit 3;

保存された抽出条件を確認する show create view ビュー名;

show create view top3;

viewを削除する

drop view top3;

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

OSがCatalina以降の環境構築

Command Line Toolsを用意

Command Line ToolsはWebアプリケーション開発に必要なソフトウェアをダウンロードするために必要な機能です。

ターミナルからCommand Line Toolsをインストール

ターミナル
$ xcode-select --install

出てくるポップアップには「インストール」→「同意する」→「完了」の順にクリック。

Homebrewを用意

Homebrewというソフトウェア管理ツールを導入します。

ターミナル
$ cd  # ホームディレクトリに移動
$ pwd  # ホームディレクトリにいるかどうか確認
$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"  # コマンドを実行

※処理に時間がかかる可能性のある操作

処理が進んでいくと、「press RETURN to continue or any other key to abort」(「続けるにはエンターキーを、やめるにはそれ以外の入力をしてください」)と表示されるので、ここではエンターキーを入力して先に進めましょう。

さらに、「password: :key2:」と表示されたら、PCのパスワードを入力してください。
ターミナル上でパスワードを入力しても文字は表示されませんが、間違いなく入力はされています。パスワードを入力し終わったらエンターキーを押してください。

その後、ダウンロードが完了し、再びコマンドを入力できるようになれば成功です。

Homebrewがインストールされているか確認

以下のコマンドを実行しましょう。

ターミナル
$ brew -v

Homebrewがインストールされているかを確認します。以下のように、Homebrewのバージョン情報が表示されれば無事にインストールされています。

ターミナル
$ brew -v
Homebrew 2.1.13

Homebrewをアップデート

ターミナル
$ brew update

Homebrewの権限を変更

ターミナル
$ sudo chown -R `whoami`:admin /usr/local/bin

rbenv と ruby-buildをインストール

ターミナル
$ brew install rbenv ruby-build

rbenvをどこからも使用できるようにする

ターミナル
$ echo 'eval "$(rbenv init -)"' >> ~/.zshrc

zshrcの変更を反映させる

$ source ~/.zshrc

readlineをinstallし、どこからも使用できるようにする

ターミナルのirb上で日本語入力を可能にする設定を行うために、以下のコマンドでインストールしましょう。

ターミナル
$ brew install readline
$ brew link readline --force

rbenvを利用してRubyをインストール

Webアプリケーション開発用のRubyをインストールします。以下のコマンドを実行しましょう。

ターミナル
$ RUBY_CONFIGURE_OPTS="--with-readline-dir=$(brew --prefix readline)"
$ rbenv install 2.5.1

※処理に10分程度かかる可能性のあるコマンドです。
2.5.1と書いてあるのは今回インストールするRubyのバージョンです。

利用するRubyのバージョンを指定

インストールしたRuby 2.5.1を使用するために、以下のコマンドを実行しましょう。

ターミナル
$ rbenv global 2.5.1

rbenvを読み込んで変更を反映させる

ターミナル
$ rbenv rehash

Rubyのバージョンを確認

ターミナル
$ ruby -v

Rubyのバージョンが、先ほどインストールした2.5.1であることが表示されれば完了です。

MySQLのインストール

MySQLは、Webアプリケーションにおけるデータを蓄積する場所のことです。

ターミナル
$ brew install mysql@5.6

※処理に時間のかかる可能性があるコマンドです。

MySQLの自動起動設定をする

MySQLは本来であればPC再起動のたびに起動し直す必要がありますが、それは面倒であるため、自動に起動するようにしておきましょう。

ターミナル
$ mkdir ~/Library/LaunchAgents 
$ ln -sfv /usr/local/opt/mysql\@5.6/*.plist ~/Library/LaunchAgents
$ launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mysql\@5.6.plist 

mysqlコマンドをどこからでも実行できるようにする

ターミナル
# mysqlのコマンドを実行できるようにする
$ echo 'export PATH="/usr/local/opt/mysql@5.6/bin:$PATH"' >> ~/.zshrc
$ source ~/.zshrc
# mysqlのコマンドが打てるか確認する
$ which mysql
# 以下のように表示されれば成功
/usr/local/opt/mysql@5.6/bin/mysql

mysqlを起動を確認

ターミナル
# mysqlの状態を確認するコマンドです
$ mysql.server status

# 以下のように表示されれば成功
 SUCCESS! MySQL running

Railsを用意

Rubyの拡張機能(gem)を管理するためのbundler(バンドラー)をインストールします。

ターミナル
$ gem install bundler

Railsをインストール

ターミナル
$ gem install rails --version='5.2.3'

rbenvを再読み込み

ターミナル
$ rbenv rehash

Railsが導入できたか確認

以下のコマンドを実行して、Rails 5.2.3が表示されれば問題なくインストールが完了しています。

ターミナル
$ rails -v

Node.jsを用意

Railsを動かすためにはnode.jsが必要となり、それをHomebrewを用いてインストールします。

Node.jsのインストール

ターミナル
$ brew install nodejs

この時、最後にError: node 13.10.0 is already installedと表示されても問題ありません。

Node.jsが導入できたか確認

以下のコマンドを実行して、v13.10.0のようにバージョンが表示されれば、問題なくインストールが完了しています。

ターミナル
$ node -v

以上でWebアプリケーション開発のための環境構築は完了です!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

mysqlの本当に有った怖い話 リンク集

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

mysqlの怖い話 リンク集

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MySQLで3億レコード物理削除した話

MySQLで3億レコード物理削除した話

はじめに

こんにちは。webエンジニア社会人をしている kanta13jp1 です。
タイトル通り。MySQLで3億レコード物理削除した話。
ちょっとハマったので備忘録。

はじまりはアラート

はじまりはアラートだった。
僕が運用・保守しているバッチサーバでは、mysqlからちょうど直近1ヶ月分のデータを毎日1回selectする定期処理をしている。

いつもなら1時間程度で終わる処理のはずが、その日は7,8時間経っても終わらずアラートが鳴り止まない.....。

原因追求

とりあえずリトライしたり、ログ見たりしたもののあんまり悪いところがなかった。
クエリもちゃんとindex効いてる。なんでだろうと思ったらDBの容量が結構大きくなっていたことに気づいた。

hoge_table | 350'000'000 |

3億5千レコード。インデックスちゃんと効いてたので多分普通に遅いだけっぽい。

必要なデータ取得は1ヶ月分である12'000'000件ほど。このselectクエリが時間かかってトランザクションが長く失敗しているようだった。

DB

基本的に毎日400'000件ぐらいinsertされてレコードが増えているこのテーブル。
データ取得は要件的には直近1ヶ月分だけあれば良いので、それだけ持てばよいのだが生憎rotate処理は入っていなかった。

自分が開発したものではなく引き継いだものだったのだが、その時点では何も言われていなかったので技術的負債のパスをもらってしまった感じである。

日々のinsertでデータが大きくなり、ついに限界を迎えたときに僕のターンだったというわけだ。

これだけ大きくなるならパーティション切っててほしかったものの、それも残念ながらなかった。

改修

一旦ロジックに手を加えるよりはDB軽くして様子見るほうが工数少ないだろうという方針になった。
3億レコード消せばかなり変わるだろう、ということでdeleteを打つことに......。このときはうまく行くと思っていた......。

対応その1

バックアップもしっかりとって、意気揚々とクエリを打ち始めた。

「クエリ打ちまーす」

DELETE FROM hoge_table WHERE create_time <= 'YYYY-MM-DD HH:MM:SS';

「...」

「...」

なんか反応がない、やっぱ時間かかるかあとか思いつつdbのgrafana眺めてたらdisc busyがめちゃめちゃ上がっていた。

「yabeeeeeeeee」

とりあえずクエリを止めた。

対応その2

一回で削除するには量が多すぎたことを反省した。dbのレプリケーション時間も考慮してこまめに削除することが良さそう。
1'000'000件ずつぐらい削除できるスクリプト書いて処理することにした。

「実行しまーす」

これでうまく行くと思っていた......。

対応その3

対応その2はどこへ......。処理はうまくいっていたのだが、時間がとてもかかることが判明した。
負荷をかけずに丁寧にやると約2週間必要だった。が、それではサービス要件を満たせず、やむなく中断。

そして対応その3である。

テーブルcopyしてrename

なんかdeleteが負荷大きくて良くないのでは。と思いinsertで欲しいテーブルを無から作ろうという方針に切り替えた。

| hoge_table     | 350'000'000|
| tmp_hoge_table |  50'000'000|

レコード数的には上記のような状態になればよいので、insertするほうがデータ処理も1/7程度になって速いはずである。

テーブル作ったあとはrenameしてマスターテーブルとして使い、今の3億レコードテーブルはdropすればokなはず。
truncateやdropはdeleteと違い負荷が少ないのは知っていたので、この方針に。

実行

「クエリ打ちまーす」

INSERT INTO tmp_hoge_table SELECT FROM hoge_table create_time > 'YYYY-MM-DD HH:MM:SS';

「...」

「...」

「お...?」

対応その4

うまく行くかと思ったが、insert終わったあとに無限にエラー吐かれた。mysql怖い。
もう本番作業したくねえよ〜って気持ちでいっぱいだった。

まあよく考えると、多分これも1回でinsertしすぎということなんだろう。
とりあえず1日分だけinsertしてみたらうまく行った。

「おお!」

このあとは丁寧丁寧に1日分ずつinsert。1ヶ月ぶんあればいいので35回日分を対応。

テーブルrename

ここはすんなりいった。めでたし。

アラート、止まる

バッチ処理の速度も回復した。
今まで1時間かかってたのに2分ぐらいで終わるようになった(は?)

問題も解決したのを確認できたので、3億レコードテーブルはdropした。
drop tableに爽快感を覚えるのは初めてだった。

まとめ。

他人のバッチ処理のローテート処理忘れでこんなに苦しむとは、って思った機会でした。
些細な設計の粗さが運用として現れて工数を奪うんだなあ......。

DBにくわしく

あなたはdeleteするときレプリケーション負荷など気にしてますか?
mysqlに優しくしましょう。

まあ今回の内容とか知ってる人は全然困るところじゃないとは思うんですが。
知識がないと難しいねーって。

cassandraでdelete多くて死んだパターンも昔経験したので何か近いものがあるのかなあとか思ったり。

また勉強したら記事にでもまとめます。

さいごに

※軽い感じに見えるけど実際はめちゃめちゃ慎重にチームでダブルチェックしながら作業進めてたよ。本番dbって怖いよね。

ではでは。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MySQL5.7でGenerated Columnを作成したがmysqldumpしたデータをリストアできなかった話

はじめに

問題が発生したテーブルですが、mysqlの全文検索インデックスを設定したテーブルで、全文検索インデックスはGenerated Column(Stored)で生成したカラムに貼ってありました。mysqldumpを取り、リストを行った所下記エラーが発生しました。

ERROR 3105 (HY000) at line XXX: The value specified for generated column 'XXX' in table 'XXXX' is not allowed.

発生環境

Webサーバ: EC2
DB: RDS(mysql5.7)

解決方法

本事象ですが、EC2にインストールしていた、mysql clientが5.6 のため発生した不具合でした。

mysql clientが5.6以前で、mysqldumpを取った際にGenerated Columnは、通常カラムと同様の扱いとなり、insert文に対象カラムの情報が記載されてしまい上記エラー発生します。

同一問題に当たった場合は、--complete-insert を使ってカラムを下記だして状況確認するのが良いかと思います。clientのバージョンが5.7系であれば、Generated Columnはinsert文に対象カラムとして表示されないはずです。

おわりに

今回は、全文インデックスを張る関係で、Generated ColumnはStoredとしていましたが、Viewの場合にmysqldump実行時にエラーが発生するバグが挙がっています。
Generated Column(View Bug)https://bugs.mysql.com/bug.php?id=79148

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む