RDBMS
# データベースとは
- B-Tree/B+TreeLSMツリーと呼ばれる平衡N分木で構築されたデータの集合。メモリ/実行時間最適化、排他制御をよしなにやってくれます。
- やり取りに人間がわかりやすい言葉
DDL(Data Definition Language) DML(Data Manipulation Language) DCL(Data Control Language)を使ってDBを操作します。例えばStructured Query Language(SQL)などがあります。 - データベースシステムとSQLはごっちゃにして言われやすいので注意。例えば、MariaDBはMySQLから派生した
Relational Database Management System(RDBMS)の一種だとか、Not only SQL(NoSQL)はクラウドのDBに対してネットワーク伝送コストを避けて最適化された非RDBMSで、MongoDBやAWSのDynamoDB, Redisがそれに含まるなど。
# 具体的にどんな処理がされているのか
工事中 :::spoiler https://zenn.dev/tzkoba/articles/bb6d31d46be8b3
コネクションプール クエリパーサ クエリーキャッシュ クエリプランナー クエリエクスキュータ アクセスメソッド バッファプールマネージャ = ストレージエンジン? ディスクマネージャ
実行順序 FROM句 JOIN句 WHERE句 GROUP BY句 HAVING句 SELECT句 ORDER BY句 LIMIT句
アクセスメソッドCRUD
memcached Redis
レプリケーション
テンポラリーテーブル
クラッシュリカバリ Redundant Array of Independent Disks RAID 0・RAID 1・RAID 5、およびこれら3方式の組み合わせが用いられている。後にRAID 5を拡張したRAID 6が定義され、RAID 5より耐障害性が必要な場面で利用されている。 二重書き込みバッファー トランザクションログ
クラスタデータベース セカンダリインデックス キー セカンダリキー バリュー プライマリーキー クラスタードインデックス テーブルをB+Treeに入れる
Memcomparable format
シリアル 数字の羅列 シーケンス 順番に並ぶ数字列
負荷分散技術 水平分割(シャーディング) レコード単位で分割 垂直分割 カラム単位で分割
ワークラウンド 回避策 ワークロード 仕事量
ストレージエンジン データ変換 インデックス メモリ利用 トランザクション 同時実行性(排他制御) ユニークファンクション(MyISAMの空間情報インデックスなど) innoDB : MySQLでもっとも汎用のストレージエンジン
ACID A: 原子性 C: 一貫性 I: 分離性 D: 持続性
MySQL InnoDB memcached Plugin https://qiita.com/hypermkt/items/ccfb47e69c4a6a3ce09a プラグインって何のプラグイン? これってmemcachedと何が違うの
MEMORY ストレージエンジン https://dev.mysql.com/doc/refman/5.6/ja/memory-storage-engine.html ストレージエンジンをMEMORYにするのはかなり注意が必要(NaruseJunがそれでメモリ使い果たして鯖爆破していたはず)
INVISIBLE COLUMNS *でとりだされない INSERT RETURNING FOREIGN KEY https://www.dbonline.jp/mysql/table/index11.html :::
# Collation(照合順序)
文字列をどうエンコーディングしてB+ツリーにどうソートして突っ込むかを設定できます。DB単位、テーブル単位、カラム単位で設定可能。
| |
文字コード_言語名_比較法
# 文字コード(Character Set)
utf8とかeucとかが入ります。 cp932やbig5などは危険なエンコーディングらしい(しらんけど)
conoHaがこれでやらかしていたらしい traP SysAd TechBook より データベースメンテナンスで⼤わらわ!
2019年8⽉6⽇夜 ConoHaのマネージドDBでメンテナンスがありました。SysAd班で はメンテナンスの存在を知らず、急にtraQなどが機能しなくなったため⼀瞬混乱が起き ました。しかしその後すぐ、@takashi_trapがメンテナンスであることをアナウンスし混乱 は収束しました。 しかし、本当の混乱はメンテナンス後に発⽣したのです。traQの復旧によりメンバー がtraQに戻ってきたのですが、下のような投稿がいろんなチャンネルで出始めたので す。 図2.6: 表⽰名が壊れたメンバーの投稿(修正後スクリーンショットを撮った) その後すべてのサービスのデータを確認してみると、すべてのサービスで⼀部の絵⽂ 字データが破損していることが確認されました。班内で検討したところ、おそらく「寿司ビ ール問題」として有名な、utf8mb4のデータをutf8として扱ってしまったことによる4バイト ⽂字の破損であるだろうという結論に⾄りました。 ConoHaに問い合わせてみましたが、私達の推測通りメンテナンスではマシンの⼊れ 替えのためにデータのバックアップを⾏なっており、その際にutf8でバックアップを取っ たとのこと。ConoHa側が持っている完全なバックアップは2⽉時点のものでそれ以降の データを復旧することは不可能であると回答がありました*3。外部に公開されている Blogサービスのみ、たまたま2週間ほど前にBlogサービスのバージョンアップ検証を⾏ うために取っていたバックアップから差分を復旧することで対処しました。 まさかこんなことってあるんですねぇ……となった事件でした
# 言語名
japaneseやthaiやgeneral、unicodeなどが入ります。 generalやunicodeはマルチリンガルの事(utf8にjapaneseはない)。
# 比較法
_ci _cs _binのいずれか(で終わる)
_ci: 大文字と小文字が区別されない _cs: 大文字と小文字が区別される _bin: バイナリ
# utf8_general_ciとutf8_unicode_ciの使い分け
unicode の方はあいまいな照合が可能です。全角、半角、大文字、小文字を無視して一致するものを検索できます。
たとえば、検索文字にMySQLを指定した時と、mysqlを指定した時の検索結果は同じになります。
general の方はその逆で、厳密に違いとして認識され先の例の検索結果は異なります。
どちらも項目の用途によって使い分けるのが、あるべき姿なのでは無いかと思います。
utf8mb4_binのがutf8mb4_general_ciより少しはやいらしい
https://yakst.com/ja/posts/5431
MySQL8ならutf8mb4_0900_binを試してみる
https://qiita.com/hmatsu47/items/d66830c8a00c21f5edad
# トランザクション
INSERT, UPDATE文を複数送るとき、その一部だけがデータベースに反映されると、一時的にせよ、データベース全体としてデータが不整合な状態となります。トランザクションを使うことでそれらを同時に実行させられます。
BEGINから始まりCOMMIT/ROLLBACKで終わる。
WAL(Write Ahead Logging)
TODO: FOR UPDATEとの違い FOR UPDATE(先行して行ロックを獲得したトランザクションがロックを開放する/ロックがタイムアウトするまで待たされる) NOWAIT(ロックが獲得できなかったときは即時にエラーを返す) SKIP LOCKED(即時に獲得可能なロックのみ獲得して結果を返す) https://www.informit.com/articles/article.aspx?p=29312
| BEGIN文 | SAVEPOINT文 |
|---|---|
| BEGIN | SAVEPOINT hoge |
| COMMIT | RELEASE SAVEPOINT hoge |
| ROLLBACK | ROLLBACK TO SAVEPOINT hoge |
| |
# PreparedStatement
INSERT文など値は違えど同じクエリを大量に実行したいとき毎回クエリを解析せず最初に1回解析すれば後はそれを使い回して高速化しようという機能です。(多分パースしてクエリプランナーに突っ込んだ状態にしてあるだけ)
- Go標準のSQLパッケージはプレースホルダを用いたクエリは暗黙的にPreparedStatementを使っている
- 同じクエリではないとき段階を踏む上でコストが掛かり遅くなる(ADMIN PREPAREが多くなる)
そこで
interpolateParams=trueを使ってPreparedStatementを減らせる http://dsas.blog.klab.org/archives/52191467.html - トランザクション中にPreparedStatementするときは先にCloseしてCommitしないと不整合が起こる
- クエリのプレースホルダーはSQLインジェクション対策にもなる。fmt.Sprintf()で作らないようにする。
| |
# 生成カラム(generated column)
https://qiita.com/hmatsu47/items/128ece7276e4deac1477 他のカラムのデータを使って新しいカラムを作る
- VIRTUAL トランザクションが入ったときにデータを生成する
- STORED INSERTしたときにデータを生成する
NOT NULLを用いれば制約に合わないものがきたらエラーを吐かせて、データに制約を作ることができる CHECKでやれって話 https://yakst.com/ja/posts/2834 VIRTUALのとき仮想列と呼びそれを使ったINDEXを仮想インデックスと呼ぶ この設計において、仮想列は簡単に追加して削除することができ、かつテーブル全体をリビルドする必要もない。これにより関連するテーブルのスキーマ変更がとても簡単かつ高速になる。
高速な仮想列の管理
mysql> ALTER TABLE t ADD new_col INT GENERATED ALWAYS AS (a - b) VIRTUAL;
# メモリ最適化
https://dev.mysql.com/doc/refman/5.6/ja/data-size.html
MEDIUMINT INTの25%削減
NOT NULL null確認の処理がなくなる
できるだけ少なく https://phpjavascriptroom.com/?t=mysql&p=columntype
# キーキャッシュ
MyISAM https://dev.mysql.com/doc/refman/5.6/ja/myisam-key-cache.html テーブルブロックとは?
ページングに注意すべきキャッシュ InnoDB バッファプール MyISAM キーキャッシュ MySQL クエリーキャッシュ
頻繁な更新を実行するアプリケーションでは、多くの場合に少数のカラムのある多数のテーブルを使用し、大量のデータを解析するアプリケーションでは、多くの場合に多数のカラムのある少数のテーブルを使用します。
正規形
InnoDB は、ほとんどのデータまたはすべてのデータをメモリーに保持する汎用的で永続的な方法を提供
tmpfs セッションとは?
# ORM O/Rマッパー
開発効率を上げる為のSQLのラッパー(クエリービルダー) ex.) gorm O/Rマッパーによるトラブルを未然に防ぐ (slideshare.net)
# isolation level
複数のトランザクションが1つのテーブルを操作するときの不整合についてどの程度許容するか
- READ UNCOMMITTED … COMMIT されてないトランザクションの変更を参照できる
- READ COMMITTED … COMMIT されたトランザクションの変更を参照できる
- REPEATABLE READ … COMMIT されたトランザクションの追加を参照できる
- SERIALIZE … 参照不可
2以降を実現する為には SELECT で共有ロック, UPDATE INSERT で専有ロックを取得すればよい. ロックの取得はパフォーマンスを下げるのでなるべくしたくない. そこでMVCC .
# MultiVersion Concurrency Controll: MVCC
DB_ROW_ID… 行IDDB_TRX_ID… 最後にupdateしたトランザクションIDDB_ROLL_PTR… レコードの過去の値を持つundo log recordへのポインタ
参照トランザクションIDが DB_TRX_ID より大きいなら変更後の値を参照, 小さいなら undo log record から探して参照, 追加したトランザクションIDより小さいなら参照できない.
# Conflict-free replicated data type
CAPの定理
- Partition Tolerance: ネットワークが故障しても
- Consistency: データの整合性をもって
- Availability: 読書が常にできる
3つ同時に満たすことはできなくて、満たせても2つまでという定理
APを満たす -> Conflict-free replicated data type
可換な操作のみ扱い、後でマージする -> ネットワークに繋がっていなくても操作可能! それぞれのDBがgitのブランチみたいな気持ち