カテゴリー「mariadb」

まず自分自身がMariaDBの生成カラム周りおよびJSONについて、

以下2点勘違いをしていた。

  • MariaDBでもMySQLと同様に、VIRTUAL COLUMNにインデックスを張ることができる(すいません、できないと思ってました。。)
  • MariaDBでもCHECK制約を使うことで、「JSONの正しさ」を保証できる(すいません、できないと思ってました。。)

以前書いた記事にも訂正を追記しておきました。

 

というわけで、MariaDB10.2.17、10.3.10のバージョンで生成カラムについて見ていきます。


ではまず、以下のようなテーブルを作ってみます。

CREATE TABLE `mail` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`to` varchar(255) NOT NULL,
`cc` varchar(255),
`bcc` varchar(255),
`subject` varchar(255) NOT NULL,
`body` json NOT NULL,
`addrs` text AS (CONCAT_WS(',', `to`, `cc`, `bcc`)) PERSISTENT,
`sign` varchar(255) AS (JSON_VALUE(`body`, '$.sign')) VIRTUAL,
CHECK (JSON_VALID(`body`)),
PRIMARY KEY (`id`),
FULLTEXT KEY `mail_fidx01` (`addrs`),
KEY `mail_idx01` (`sign`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

ちょっと長いのですが、ポイントは以下の通り。

  1. addrsカラムに対して、PERSISTENTタイプの生成カラムを利用して、全文検索INDEXを張る
  2. bodyカラムに対して、JSONの型チェックを行う
  3. signカラムに対して、VIRTUALタイプの生成カラムを利用して、JSONの部分抽出を行い、セカンダリーINDEXを張る

1はカラムを結合した状態を全文検索にしたい場合、

2はJSONの正しさを保証したい場合、

3はJSONの中の特定のキーを条件に高速にデータアクセスしたい場合、

に用いられるような想定です。

この状態のテーブルを見てみます。

MariaDB [test]> desc mail;
+---------+--------------+------+-----+---------+-------------------+
| Field   | Type         | Null | Key | Default | Extra             |
+---------+--------------+------+-----+---------+-------------------+
| id      | int(10)      | NO   | PRI | NULL    | auto_increment    |
| to      | varchar(255) | NO   |     | NULL    |                   |
| cc      | varchar(255) | YES  |     | NULL    |                   |
| bcc     | varchar(255) | YES  |     | NULL    |                   |
| subject | varchar(255) | NO   |     | NULL    |                   |
| body    | longtext     | NO   |     | NULL    |                   |
| addrs   | text         | YES  | MUL | NULL    | STORED GENERATED  |
| sign    | varchar(255) | YES  | MUL | NULL    | VIRTUAL GENERATED |
+---------+--------------+------+-----+---------+-------------------+
8 rows in set (0.002 sec)

MariaDB [test]> show index from mail;
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name    | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| mail  | 0          | PRIMARY     | 1            | id          | A         | 0           | NULL     | NULL   |      | BTREE      |         |               |
| mail  | 1          | mail_idx01  | 1            | sign        | A         | 0           | NULL     | NULL   | YES  | BTREE      |         |               |
| mail  | 1          | mail_fidx01 | 1            | addrs       | NULL      | NULL        | NULL     | NULL   | YES  | FULLTEXT   |         |               |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.000 sec)

生成カラムの情報がdescのExtraにも表現されていますね。

ちなみに、生成カラムは「NOT NULL DEFAULT ・・・」は付けられないようで、生成カラムの評価ができない(失敗?)の場合は、NULLが入る仕様のようです。

 

次に以下のようなデータを流し込んで、結果を見てみます。

INSERT INTO `mail` (`to`, `cc`, `bcc`, `subject`, `body`) VALUES ('to-00001@example.com', 'cc-00001@example.com', 'bcc-00001@example.com', 'subject-00001', '{"sign": "sign-00001", "message": "message-00001"}');
INSERT INTO `mail` (`to`, `cc`, `bcc`, `subject`, `body`) VALUES ('to-00002@example.com', 'cc-00002@example.com', null , 'subject-00002', '{"sign": "sign-00002", "message": "message-00002"}');
INSERT INTO `mail` (`to`, `cc`, `bcc`, `subject`, `body`) VALUES ('to-00003@example.com', null , null , 'subject-00003', '{"sign": "sign-00003", "message": "message-00003"}');
INSERT INTO `mail` (`to`, `cc`, `bcc`, `subject`, `body`) VALUES ('to-00004@example.com', null , null , 'subject-00004', '{"message": "message-00004"}');
MariaDB [test]> select * from mail\G;
*************************** 1. row ***************************
     id: 1
     to: to-00001@example.com
     cc: cc-00001@example.com
    bcc: bcc-00001@example.com
subject: subject-00001
   body: {"sign": "sign-00001", "message": "message-00001"}
  addrs: to-00001@example.com,cc-00001@example.com,bcc-00001@example.com
   sign: sign-00001
*************************** 2. row ***************************
     id: 2
     to: to-00002@example.com
     cc: cc-00002@example.com
    bcc: NULL
subject: subject-00002
   body: {"sign": "sign-00002", "message": "message-00002"}
  addrs: to-00002@example.com,cc-00002@example.com
   sign: sign-00002
*************************** 3. row ***************************
     id: 3
     to: to-00003@example.com
     cc: NULL
    bcc: NULL
subject: subject-00003
   body: {"sign": "sign-00003", "message": "message-00003"}
  addrs: to-00003@example.com
   sign: sign-00003
*************************** 4. row ***************************
     id: 4
     to: to-00004@example.com
     cc: NULL
    bcc: NULL
subject: subject-00004
   body: {"message": "message-00004"}
  addrs: to-00004@example.com
   sign: NULL
4 rows in set (0.000 sec)

ちゃんとデータが入っていますので、
PERSISTENTタイプのaddrsへの全文検索と、
VIRTUALタイプのsignへの検索を行ってみます。

 

・PERSISTENTタイプのaddrsへの全文検索

MariaDB [test]> select * from mail where match(addrs) against('cc-00002')\G;
*************************** 1. row ***************************
     id: 2
     to: to-00002@example.com
     cc: cc-00002@example.com
    bcc: NULL
subject: subject-00002
   body: {"sign": "sign-00002", "message": "message-00002"}
  addrs: to-00002@example.com,cc-00002@example.com
   sign: NULL
1 row in set (0.001 sec)

MariaDB [test]> explain select * from mail where match(addrs) against('cc-00002')\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: mail
         type: fulltext
possible_keys: mail_fidx01
          key: mail_fidx01
      key_len: 0
          ref:
         rows: 1
        Extra: Using where
1 row in set (0.000 sec)

・VIRTUALタイプのsignへの検索

MariaDB [test]> select * from mail where sign = 'sign-00003'\G;
*************************** 1. row ***************************
     id: 3
     to: to-00003@example.com
     cc: NULL
    bcc: NULL
subject: subject-00003
   body: {"sign": "sign-00003", "message": "message-00003"}
  addrs: to-00003@example.com
   sign: sign-00003
1 row in set (0.001 sec)

MariaDB [test]> explain select * from mail where sign = 'sign-00003'\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: mail
         type: ref
possible_keys: mail_idx01
          key: mail_idx01
      key_len: 1023
          ref: const
         rows: 1
        Extra: Using where
1 row in set (0.001 sec)

 

ちょっと件数少ないですが、両方共INDEXが効いていることがわかります。

 

生成カラムって実際どのくらい使われているのかわかりませんが、うまく使うことで、機能追加にも柔軟な対応ができそうな予感です。

生成カラムの進化はこれからも期待しています。

おっと、INSTANT ADDは、生成カラムには効かないので、ご注意ください。INSTANT対応も今後はあるのでは、と期待してます。

 

以上

投稿日時:2018年11月01日 16:38   カテゴリー:mariadb   [コメントがあればどうぞ]

pt-online-schema-changeをslaveに対して実行した場合に痛い目見たので、その備忘録。

 

そもそもの話、master側で不要なINDEXをslaveのみ張ってました。

OLTP側ではいらないINDEXだけど、集計とかであると嬉しいINDEXってやつですね。

そして、slaveに張っているINDEXをpt-oscでオンラインで張替えをしようとしたら、

リレーログからの取り込みが、旧テーブルに行ってしまい、

pt-oscで作成される新テーブルに入らなかったいうオチ。。。

その結果、レプリケーションの不整合が起きて、最初から構築するという目にあった。。

 

このような場合、素直にstop slaveを掛けてからDDLを実行すれば良かったです。。

とはいえ、リレーログからのデータ取り込みの際、pt-oscで実行しているとダメなことがわかったので、

もうちょっとこのあたりについて調べてみようかと思います。

 

あ、binlog_row_image=FULLだったし、MariaDB10.3だからflashback使えば、

もっと短時間で復旧できたかも、、って書いているときに思いました。。

 

以上

投稿日時:2018年10月22日 12:48   カテゴリー:mariadb, mysql   [コメントがあればどうぞ]

前回の記事で、unionの条件判定が10.2から変更になっていると記載しましたが、

どうやら、10.2から追加されたoptimizer_switchの動作によるものらしい。

具体的には、

condition_pushdown_for_derived=on

というパラメータに依存するようです。

 

実際に、上記パラメータを切り替えてテストしてみた。

 

・offのとき

MariaDB [test]> set optimizer_switch='condition_pushdown_for_derived=off';
Query OK, 0 rows affected (0.000 sec)

MariaDB [test]> explain select * from (select * from users union all select * from users) as t where id = 7542;
+------+-------------+------------+------+---------------+------+---------+------+---------+-------------+
| id   | select_type | table      | type | possible_keys | key  | key_len | ref  | rows    | Extra       |
+------+-------------+------------+------+---------------+------+---------+------+---------+-------------+
| 1    | PRIMARY     | <derived2> | ALL  | NULL          | NULL | NULL    | NULL | 1993522 | Using where |
| 2    | DERIVED     | users      | ALL  | NULL          | NULL | NULL    | NULL | 996761  |             |
| 3    | UNION       | users      | ALL  | NULL          | NULL | NULL    | NULL | 996761  |             |
+------+-------------+------------+------+---------------+------+---------+------+---------+-------------+
3 rows in set (0.001 sec)

 

・onのとき

MariaDB [test]> set optimizer_switch='condition_pushdown_for_derived=on';
Query OK, 0 rows affected (0.000 sec)

MariaDB [test]> explain select * from (select * from users union all select * from users) as t where id = 7542;
+------+-------------+------------+-------+---------------+---------+---------+-------+------+-------------+
| id   | select_type | table      | type  | possible_keys | key     | key_len | ref   | rows | Extra       |
+------+-------------+------------+-------+---------------+---------+---------+-------+------+-------------+
| 1    | PRIMARY     | <derived2> | ALL   | NULL          | NULL    | NULL    | NULL  | 2    | Using where |
| 2    | DERIVED     | users      | const | PRIMARY       | PRIMARY | 4       | const | 1    |             |
| 3    | UNION       | users      | const | PRIMARY       | PRIMARY | 4       | const | 1    |             |
+------+-------------+------------+-------+---------------+---------+---------+-------+------+-------------+
3 rows in set (0.000 sec)

 

というように、

condition_pushdown_for_derived

のパラメータによって上記の差異がでる。

 

で、さらに気になったのが、

10.2から、

mrr=off
mrr_cost_based=off

に変更されている。

 

mrrはセカンダリーインデックスのIO負荷軽減のものであったかと思うが、

このあたりの絡みでパフォーマンスにどう影響があるのか、再度調べてみようと思う。

なお、MySQL8ではonのままであった。

 

以上

投稿日時:2018年10月02日 17:45   カテゴリー:mariadb   [コメントがあればどうぞ]

unionする前にwhereをするのと、

unionした後にwhereをする場合、

mysqlにおいて、差異はあるのかを確認してみた。

 

動機としては、

「unionする前にwhereをする」のと「unionした後にwhereをする」が同パフォーマンスであれば、

multisourceでviewを作っておいても十分高速に引ける可能性がある、と思ったところです。

いろいろなバージョンで試してみました。

 

予め以下のようなテーブルを作成しておき、100万件登録しておきます。

> desc users;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id    | int(11)      | NO   | PRI | NULL    |       |
| email | varchar(128) | NO   |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

 

(MySQL5.6)

mysql> explain select * from (select * from users union all select * from users) as t where id = 7542;
+------+--------------+------------+------+---------------+-------------+---------+-------+--------+-----------------+
| id   | select_type  | table      | type | possible_keys | key         | key_len | ref   | rows   | Extra           |
+------+--------------+------------+------+---------------+-------------+---------+-------+--------+-----------------+
| 1    | PRIMARY      | <derived2> | ref  | <auto_key0>   | <auto_key0> | 4       | const | 10     | NULL            |
| 2    | DERIVED      | users      | ALL  | NULL          | NULL        | NULL    | NULL  | 996473 | NULL            |
| 3    | UNION        | users      | ALL  | NULL          | NULL        | NULL    | NULL  | 996473 | NULL            |
| NULL | UNION RESULT | <union2,3> | ALL  | NULL          | NULL        | NULL    | NULL  | NULL   | Using temporary |
+------+--------------+------------+------+---------------+-------------+---------+-------+--------+-----------------+
4 rows in set (0.12 sec)

mysql> explain select * from (select * from users where id = 7542 union all select * from users where id = 7542) as t;
+------+--------------+------------+-------+---------------+---------+---------+-------+------+-----------------+
| id   | select_type  | table      | type  | possible_keys | key     | key_len | ref   | rows | Extra           |
+------+--------------+------------+-------+---------------+---------+---------+-------+------+-----------------+
| 1    | PRIMARY      | <derived2> | ALL   | NULL          | NULL    | NULL    | NULL  | 2    | NULL            |
| 2    | DERIVED      | users      | const | PRIMARY       | PRIMARY | 4       | const | 1    | NULL            |
| 3    | UNION        | users      | const | PRIMARY       | PRIMARY | 4       | const | 1    | NULL            |
| NULL | UNION RESULT | <union2,3> | ALL   | NULL          | NULL    | NULL    | NULL  | NULL | Using temporary |
+------+--------------+------------+-------+---------------+---------+---------+-------+------+-----------------+
4 rows in set (0.00 sec)

 

(MySQL5.7)

mysql> explain select * from (select * from users union all select * from users) as t where id = 7542;
+----+-------------+------------+------------+------+---------------+-------------+---------+-------+--------+----------+-------+
| id | select_type | table      | partitions | type | possible_keys | key         | key_len | ref   | rows   | filtered | Extra |
+----+-------------+------------+------------+------+---------------+-------------+---------+-------+--------+----------+-------+
| 1  | PRIMARY     | <derived2> | NULL       | ref  | <auto_key0>   | <auto_key0> | 4       | const | 10     | 100.00   | NULL  |
| 2  | DERIVED     | users      | NULL       | ALL  | NULL          | NULL        | NULL    | NULL  | 996473 | 100.00   | NULL  |
| 3  | UNION       | users      | NULL       | ALL  | NULL          | NULL        | NULL    | NULL  | 996473 | 100.00   | NULL  |
+----+-------------+------------+------------+------+---------------+-------------+---------+-------+--------+----------+-------+
3 rows in set, 1 warning (0.00 sec)

mysql> explain select * from (select * from users where id = 7542 union all select * from users where id = 7542) as t;
+----+-------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table      | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| 1  | PRIMARY     | <derived2> | NULL       | ALL   | NULL          | NULL    | NULL    | NULL  | 2    | 100.00   | NULL  |
| 2  | DERIVED     | users      | NULL       | const | PRIMARY       | PRIMARY | 4       | const | 1    | 100.00   | NULL  |
| 3  | UNION       | users      | NULL       | const | PRIMARY       | PRIMARY | 4       | const | 1    | 100.00   | NULL  |
+----+-------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
3 rows in set, 1 warning (0.00 sec)

 

(MySQL8)

mysql> explain select * from (select * from users union all select * from users) as t where id = 7542;
+----+-------------+------------+------------+------+---------------+-------------+---------+-------+--------+----------+-------+
| id | select_type | table      | partitions | type | possible_keys | key         | key_len | ref   | rows   | filtered | Extra |
+----+-------------+------------+------------+------+---------------+-------------+---------+-------+--------+----------+-------+
| 1  | PRIMARY     | <derived2> | NULL       | ref  | <auto_key0>   | <auto_key0> | 4       | const | 10     | 100.00   | NULL  |
| 2  | DERIVED     | users      | NULL       | ALL  | NULL          | NULL        | NULL    | NULL  | 996761 | 100.00   | NULL  |
| 3  | UNION       | users      | NULL       | ALL  | NULL          | NULL        | NULL    | NULL  | 996761 | 100.00   | NULL  |
+----+-------------+------------+------------+------+---------------+-------------+---------+-------+--------+----------+-------+
3 rows in set, 1 warning (0.05 sec)

mysql> explain select * from (select * from users where id = 7542 union all select * from users where id = 7542) as t;
+----+-------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table      | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| 1  | PRIMARY     | <derived2> | NULL       | ALL   | NULL          | NULL    | NULL    | NULL  | 2    | 100.00   | NULL  |
| 2  | DERIVED     | users      | NULL       | const | PRIMARY       | PRIMARY | 4       | const | 1    | 100.00   | NULL  |
| 3  | UNION       | users      | NULL       | const | PRIMARY       | PRIMARY | 4       | const | 1    | 100.00   | NULL  |
+----+-------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
3 rows in set, 1 warning (0.00 sec)

 

(MariaDB10.1)

MariaDB [test]> explain select * from (select * from users union all select * from users) as t where id = 7542;
+------+-------------+------------+------+---------------+------+---------+------+---------+-------------+
| id   | select_type | table      | type | possible_keys | key  | key_len | ref  | rows    | Extra       |
+------+-------------+------------+------+---------------+------+---------+------+---------+-------------+
| 1    | PRIMARY     | <derived2> | ALL  | NULL          | NULL | NULL    | NULL | 1994176 | Using where |
| 2    | DERIVED     | users      | ALL  | NULL          | NULL | NULL    | NULL | 997088  |             |
| 3    | UNION       | users      | ALL  | NULL          | NULL | NULL    | NULL | 997088  |             |
+------+-------------+------------+------+---------------+------+---------+------+---------+-------------+
3 rows in set (0.01 sec)

MariaDB [test]> explain select * from (select * from users where id = 7542 union all select * from users where id = 7542) as t;
+------+-------------+------------+-------+---------------+---------+---------+-------+------+-------+
| id   | select_type | table      | type  | possible_keys | key     | key_len | ref   | rows | Extra |
+------+-------------+------------+-------+---------------+---------+---------+-------+------+-------+
| 1    | PRIMARY     | <derived2> | ALL   | NULL          | NULL    | NULL    | NULL  | 2    |       |
| 2    | DERIVED     | users      | const | PRIMARY       | PRIMARY | 4       | const | 1    |       |
| 3    | UNION       | users      | const | PRIMARY       | PRIMARY | 4       | const | 1    |       |
+------+-------------+------------+-------+---------------+---------+---------+-------+------+-------+
3 rows in set (0.00 sec)

 

(MariaDB10.2)

MariaDB [test]> explain select * from (select * from users union all select * from users) as t where id = 7542;
+------+-------------+------------+-------+---------------+---------+---------+-------+------+-------------+
| id   | select_type | table      | type  | possible_keys | key     | key_len | ref   | rows | Extra       |
+------+-------------+------------+-------+---------------+---------+---------+-------+------+-------------+
| 1    | PRIMARY     | <derived2> | ALL   | NULL          | NULL    | NULL    | NULL  | 2    | Using where |
| 2    | DERIVED     | users      | const | PRIMARY       | PRIMARY | 4       | const | 1    |             |
| 3    | UNION       | users      | const | PRIMARY       | PRIMARY | 4       | const | 1    |             |
+------+-------------+------------+-------+---------------+---------+---------+-------+------+-------------+
3 rows in set (0.001 sec)

MariaDB [test]> explain select * from (select * from users where id = 7542 union all select * from users where id = 7542) as t;
+------+-------------+------------+-------+---------------+---------+---------+-------+------+-------+
| id   | select_type | table      | type  | possible_keys | key     | key_len | ref   | rows | Extra |
+------+-------------+------------+-------+---------------+---------+---------+-------+------+-------+
| 1    | PRIMARY     | <derived2> | ALL   | NULL          | NULL    | NULL    | NULL  | 2    |       |
| 2    | DERIVED     | users      | const | PRIMARY       | PRIMARY | 4       | const | 1    |       |
| 3    | UNION       | users      | const | PRIMARY       | PRIMARY | 4       | const | 1    |       |
+------+-------------+------------+-------+---------------+---------+---------+-------+------+-------+
3 rows in set (0.001 sec)

 

(MariaDB10.3)

MariaDB [test]> explain select * from (select * from users union all select * from users) as t where id = 7542;
+------+-------------+------------+-------+---------------+---------+---------+-------+------+-------------+
| id   | select_type | table      | type  | possible_keys | key     | key_len | ref   | rows | Extra       |
+------+-------------+------------+-------+---------------+---------+---------+-------+------+-------------+
| 1    | PRIMARY     | <derived2> | ALL   | NULL          | NULL    | NULL    | NULL  | 2    | Using where |
| 2    | DERIVED     | users      | const | PRIMARY       | PRIMARY | 4       | const | 1    |             |
| 3    | UNION       | users      | const | PRIMARY       | PRIMARY | 4       | const | 1    |             |
+------+-------------+------------+-------+---------------+---------+---------+-------+------+-------------+
3 rows in set (0.001 sec)

MariaDB [test]> explain select * from (select * from users where id = 7542 union all select * from users where id = 7542) as t;
+------+-------------+------------+-------+---------------+---------+---------+-------+------+-------+
| id   | select_type | table      | type  | possible_keys | key     | key_len | ref   | rows | Extra |
+------+-------------+------------+-------+---------------+---------+---------+-------+------+-------+
| 1    | PRIMARY     | <derived2> | ALL   | NULL          | NULL    | NULL    | NULL  | 2    |       |
| 2    | DERIVED     | users      | const | PRIMARY       | PRIMARY | 4       | const | 1    |       |
| 3    | UNION       | users      | const | PRIMARY       | PRIMARY | 4       | const | 1    |       |
+------+-------------+------------+-------+---------------+---------+---------+-------+------+-------+
3 rows in set (0.000 sec)

 

これ、正直言って、動機を満たす結果を得るのは無理だと思ってたが、、、

MariaDB10.2と10.3は嬉しい結果を出してくれました。

 

以上

投稿日時:2018年09月11日 20:08   カテゴリー:mariadb, mysql   [コメントがあればどうぞ]

MariaDB10.3、MySQL8から、ALTER構文にinstantの機能が導入されました。

利用できる範囲は限られていますが、その中であれば超高速でALTERが完了します。

たぶん、メタデータだけ書き換えて、実際のデータは初回アクセス時に補完する形をとっているような感じです。

 

詳細は、公式マニュアルを参考指定だければと思います。

https://mariadb.com/kb/en/library/instant-add-column-for-innodb/

https://dev.mysql.com/doc/refman/8.0/en/alter-table.html

 

実際にデータを突っ込んでみて、どのくらいALTERが高速になるか試してみました。

以下のようなテーブルを用意して、100万件のデータを入れておきます。

> desc users;
+--------+---------------------+------+-----+---------+-------+
| Field  | Type                | Null | Key | Default | Extra |
+--------+---------------------+------+-----+---------+-------+
| id     | int(11)             | NO   | PRI | NULL    |       |
| email  | varchar(128)        | NO   |     | NULL    |       |
+--------+---------------------+------+-----+---------+-------+

 

(MySQL5.7)

mysql> alter table users add column money1 bigint unsigned not null;
Query OK, 0 rows affected (2.35 sec)
Records: 0 Duplicates: 0 Warnings: 0

 

(MySQL8)

mysql> alter table users add column money1 bigint unsigned not null;
Query OK, 0 rows affected (0.16 sec)
Records: 0 Duplicates: 0 Warnings: 0

一旦drop。

mysql> alter table users add column money1 bigint unsigned not null, ALGORITHM=INSTANT;
Query OK, 0 rows affected (0.09 sec)
Records: 0 Duplicates: 0 Warnings: 0

 

(MariaDB10.3)

MariaDB [test]> alter table users add column money1 bigint unsigned not null;
Query OK, 0 rows affected (0.006 sec)
Records: 0 Duplicates: 0 Warnings: 0

一旦drop。

MariaDB [test]> alter table users add column money1 bigint unsigned not null, ALGORITHM=INSTANT;
Query OK, 0 rows affected (0.007 sec)
Records: 0 Duplicates: 0 Warnings: 0

 

MySQL5.7と比較して、超高速ですね。。

なお、MariaDB10.3もMySQL8も、デフォルトで最後尾へのadd columnはINSTANTとして扱われるようです。

 

ちなみに、MySQL8のほうが、INSTANTが扱える範囲が広いようです。

以下のような条件でINSTANTが使えるようです。(※公式より引用)

  • Adding a column. This feature is referred to as “Instant ADD COLUMN”. Limitations apply. See Section 15.12.1, “Online DDL Operations”.
  • Adding or dropping a virtual column.
  • Adding or dropping a column default value.
  • Modifying the definition of an ENUM or SET column. The same restrictions apply as described above for ALGORITHM=INSTANT.
  • Changing the index type.
  • Renaming a table. The same restrictions apply as described above for ALGORITHM=INSTANT.

 

instantが発動したかどうかは、

MariaDB10.3の場合は以下のクエリーによって確認できます。

SELECT variable_value FROM information_schema.global_status WHERE variable_name = 'innodb_instant_alter_column';

MySQL8の場合は以下。

SELECT table_id, name, instant_cols FROM information_schema.innodb_tables WHERE name LIKE '%{table_name}%';

 

条件はあるものの、MySQL8は仮想列に対するinstantにも対応しているので、結構使い勝手も広がる予感です。

とはいえ、これまでalterに非常に大きな時間・処理コストがかかっていたのが、一気に超高速になり、非常に素晴らしいと思います。

パッチを提供したTencentに感謝ですね。

 

あとは、instantで変更をかけて、その後のアクセスでどのくらいIO負荷を持っていかれるか、試してみたいな。。

 

以上

 

投稿日時:2018年09月11日 18:48   カテゴリー:mariadb, mysql   [コメントがあればどうぞ]

以前の投稿で、spider engineを使った際、

flush tables;

を使わないと、バックエンドに正常にクエリーが流れないことを記載した。

調査した結果、

spider_use_handler=1

を設定することで、正しくバックエンドにクエリーが流れることが確認できた。

上記パラメータは以下の公式にある。

https://mariadb.com/kb/en/library/spider-server-system-variables/#spider_use_handler

しかし、このパラメータはなんなのか。。

というわけで、spider関連の設定を備忘録として載せておく。

spider_bka_mode=1
spider_conn_recycle_mode=1
spider_connect_retry_count=2
spider_connect_retry_interval=1000
spider_connect_timeout=10
spider_crd_sync=0
spider_direct_dup_insert=1
spider_local_lock_table=0
spider_log_result_errors=2
spider_max_connections=0
spider_net_read_timeout=10
spider_net_write_timeout=10
spider_remote_access_charset=utf8mb4
spider_remote_autocommit=0
spider_remote_sql_log_off=0
spider_reset_sql_alloc=0
spider_sts_sync=0
spider_support_xa=0
spider_sync_autocommit=0
spider_sync_trx_isolation=0
spider_use_handler=1

別途クエリー挙動をまとめようと思います。

以上

投稿日時:2018年08月14日 16:57   カテゴリー:mariadb   [コメントがあればどうぞ]

spider engineを検証していたら、謎の挙動に出会った。

簡単に言うと、whereでpartition条件句を含めたクエリーを発行したのち、

whereがないクエリーを発行すると、partition条件句の向き先となったノードに発行先が固定されるというもの。

試したバージョンは、

MariaDB:10.3.8

Spider:3.3.13

である。

 

原因がよくわかっていないのだが、

flush tables;

コマンドを発行すると治る。。

セッションを終了しても治らない。。

 

高速化のため、spider側で何かしらキャッシュしていることが原因なのではないかと考えているが、

どうも気持ち悪く、バグなのか仕様なのかも現在はっきりしていない。

原因が判明したら、また記載しようと思います。

また、MariaDB10.1にバンドルされていた3.2.37とは動きが異なる部分が多かったので、

検証完了次第、詳細な動き(パターン)を合わせて記載出来たらと思います。

 

以上

投稿日時:2018年08月06日 18:21   カテゴリー:mariadb   [コメントがあればどうぞ]

MariaDBの以下のクラスター方式で、パフォーマンス比較をしてみた。

比較動機としては、galeraは本当に遅いか?ということを確認するためのものです。

  1. standalone(比較用)
  2. semi sync
  3. galera

 

環境はvagrantの仮想マシンで、以下構成とバージョン。

CPU:1core、MEMORY:512MB

OS:CentOS7.5

MariaDB:10.3.8

 

sysbenchの実行スクリプトは以下の通りで、${thread}の部分は1と2で実施。

$ sudo sysbench /usr/share/sysbench/oltp_read_write.lua \
--db-driver=mysql \
--table-size=100000 \
--mysql-host=192.168.35.11 \
--mysql-user=admin \
--mysql-password=adminpassword \
--time=60 \
--db-ps-mode=disable \
--threads=${thread} run

 

テストにおけるインスタンス配置は以下の通り。

1.standalone

----------
sysbench
ip:192.168.35.10
----------
 |
 |
 |
----------
db01
ip:192.168.35.11
----------

 

2.semi sync

----------
sysbench
ip:192.168.35.10
----------
 |
 |
 |
-----------------------
db01
ip:192.168.35.11
-----------------------
  |               |
  |(replication)  |(replication)
  |               |
 ----------       ----------
 db02             db03
 ip:192.168.35.12 ip:192.168.35.13
 ----------       ----------

 

3.galera

----------
sysbench
ip:192.168.35.10
----------
 |
 |
 |
-----------------------
db01
ip:192.168.35.11
-----------------------
  |                |
  |(write set)     |(write set)
  |                |
 ----------       ----------
 db02             db03
 ip:192.168.35.12 ip:192.168.35.13
 ----------       ----------

 

ざっくりパラメータは以下の通りで、条件によって、変更していく。

# --------------------------------------------------
# base
# --------------------------------------------------
server_id=${server_id}
user=mysql
bind_address=0.0.0.0
pid_file=/var/run/mysql/mysqld.pid
port=3306
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
sql_mode=TRADITIONAL
default_storage_engine=InnoDB
transaction_isolation=READ-COMMITTED
character_set_server=utf8mb4
collation_server=utf8mb4_general_ci
thread_pool_max_threads=100
thread_handling=pool-of-threads
extra_port=3307
extra_max_connections=10

# --------------------------------------------------
# network
# --------------------------------------------------
max_connections=50
max_connect_errors=999999999
connect_timeout=10
max_allowed_packet=16M
back_log=1024

# --------------------------------------------------
# logging
# --------------------------------------------------
log_output=FILE
log_error=/var/log/mysql/error.log
slow_query_log=1
long_query_time=1
log_queries_not_using_indexes=0
slow_query_log_file=/var/log/mysql/slow.log
general_log=0
general_log_file=/var/log/mysql/general.log

# --------------------------------------------------
# cache, memory
# --------------------------------------------------
query_cache_size=0
max_heap_table_size=32M
tmp_table_size=32M

# --------------------------------------------------
# session
# --------------------------------------------------
sort_buffer_size=4M
read_rnd_buffer_size=2M
read_buffer_size=512K
join_buffer_size=512K

# --------------------------------------------------
# innodb
# --------------------------------------------------
innodb_buffer_pool_load_at_startup=1
innodb_buffer_pool_dump_at_shutdown=1
innodb_buffer_pool_dump_pct=25
innodb_fast_shutdown=0
innodb_flush_log_at_trx_commit=1    // set globalで適宜変更
innodb_autoinc_lock_mode=2
innodb_doublewrite=ON
innodb_file_per_table=1
innodb_log_buffer_size=16M
innodb_buffer_pool_size=256M
innodb_flush_neighbors=0
innodb_read_ahead_threshold=0
innodb_log_file_size=64M
innodb_log_files_in_group=2
innodb_buffer_pool_instances=8
innodb_lru_scan_depth=1024
innodb_read_io_threads=1
innodb_write_io_threads=1
innodb_io_capacity=100
innodb_io_capacity_max=1000
innodb_open_files=1024
innodb_purge_threads=1
innodb_sync_array_size=2
innodb_flush_method=O_DIRECT

# --------------------------------------------------
# replication
# --------------------------------------------------
report_host=${ip_addr}
read_only=0
binlog_format=row
log_bin=mariadb-bin
max_binlog_size=128M
sync_binlog=1        // set globalで適宜変更
expire_logs_days=3
log_slave_updates=1
relay_log_recovery=1
slave_max_allowed_packet=1G
slave_net_timeout=3600
slave_parallel_threads=1
gtid_strict_mode=1

# --------------------------------------------------
# semisync
# --------------------------------------------------
{if (semi syncのときのみ)}
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=1500
rpl_semi_sync_slave_enabled=1
rpl_semi_sync_master_wait_point=AFTER_SYNC
{endif}

# --------------------------------------------------
# galera
# --------------------------------------------------
{if (galeraのときのみ)}
wsrep_on=1
wsrep_cluster_name=db-cluster
wsrep_cluster_address=gcomm://192.168.35.11,192.168.35.12,192.168.35.13
wsrep_node_address=${ip_addr}
wsrep_provider=/usr/lib64/galera/libgalera_smm.so
wsrep_sst_method=rsync
wsrep_slave_threads=1
wsrep_provider_options="gcache.recover=yes; gcache.size=1G; gcs.fc_factor=1.0; gcs.fc_limit=256; gcs.fc_master_slave=yes;"
{endif}

という前提でテストをした結果が以下の通り。

結果を見てみると、

semi sync3とgalera2は遜色がないことがわかる。

semi syncよりgaleraは遅いと思っていたが、そうとも言えないのかもしれない。

とはいえ、あくまでsysbenchの結果であり、トランザクションの量や、スレッドの量によって、

結果は変わるものなので、あくまで一つの指標として、「galeraは早くないけど、遅いとも言い切れない」ってことがわかった気がします。

 

以上

投稿日時:2018年08月03日 16:50   カテゴリー:mariadb   [コメントがあればどうぞ]

表題の通り、galeraにslaveくっつけて、slave側をmroongaとして使ってみる。

構成は以下の通り。

----------       ----------       ----------
galera01 <-----> galera02 <-----> galera03
IP:192.168.35.11 IP:192.168.35.12 IP:192.168.35.13
----------       ----------       ----------
|
|(replication)
|
----------
slave01
IP:192.168.35.14
----------

 

この構成の利点は以下の通り。

  1. mroongaをストレージモード/ラッパーモードで使う際に発生する問題点を解決可能
  2. galeraで行うことで、レプリケーションフェイルオーバ誤検知問題を回避できる。

 

1については、

・ストレージモードで扱うと、そもそもトランザクションに対応していない問題

・ラッパーモードで扱うと、rollback時にfulltextインデックスの再構築が必要になる問題

を解決できる。

2については、

・レプリケーションを多段にさせた場合、フェイルオーバを誤検知する可能性がある問題

※maxscaleのfailover toporogyを見ると、多段レプリケーションには対応していないようである。

※他のフェイルオーバツールとして、mrmは未検証、orchestoratorはMariaDBへ対応していない?ように見えた。

を解決できる。

 

さらに、galeraにしておくことで、masterをどこに向けても簡単に整合性が取れる。

現状では、slave01のmasterはgalera01になっているが、galera02をmasterとして向けてもよい。

これは、GTID(※ここではGlobal Transaction IDを指しています。Galera Transaction IDではありません。)が、

galeraクラスター間で同期が取られているためである。

 

簡単ながら、mroongaを構築する流れを記載します。

ここでは上記構成は構築済みとします。

 

・galera01

まずは、innoDBのテーブルを作成する。

[MariaDB]> create table news (
id integer not null,
search text not null,
primary key(id)
) ENGINE=InnoDB;

作成すると、galera02、galera02、slave01にも伝播する。

 

・slave01

以下のDDLでテーブル定義を修正する。

[MariaDB]> ALTER TABLE news ENGINE=Mroonga;
[MariaDB]> CREATE FULLTEXT INDEX news_fidx01 ON news(search);
[MariaDB]> show create table news;
+-------+----------------
| Table | Create Table |
+-------+----------------
| news | CREATE TABLE `news` (
`id` int(11) NOT NULL,
`search` text NOT NULL,
PRIMARY KEY (`id`),
FULLTEXT KEY `news_fidx01` (`search`)
) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 |
+-------+----------------
1 row in set (0.000 sec)

 

これで、galera01でnewsテーブルにデータを登録すると、

slave01側では全文検索が可能になる。

※galera02、galera03に登録しても、slave01側に伝播します。

 

もし、「gtid_strict_mode」というMariaDB10.3から追加されたパラメータの値を1にしていたら、

slaveのDDL流し込み時に、slave01サーバで本パラメータを一時的に無効化しておきましょう。

[MariaDB]> SET GLOBAL gtid_strict_mode=0;

この「gtid_strict_mode」というのは、レプリケーションでの整合性を取るのに優れたパラメータである。

slaveサーバにおいて、

gtid_binlog_pos > gtid_slave_pos

を許さないためのパラメータであり、gtid_strict_mode=1のままだと、

slaveの独自DDL/DMLによって、レプリケーションが停止してしまうためです。

 

あとは、slave側で、

[MariaDB]> select * from news where match(search) against('+金額');

のような全文検索クエリーが利用できる。

 

以上

投稿日時:2018年07月25日 18:06   カテゴリー:mariadb   [コメントがあればどうぞ]

MariaDB Galera Clusterで、MariaDB10.3から導入されたsequenceを使うときは、2つの注意点がある。

 

1.wsrep_auto_increment_controlの設定

wsrep_auto_increment_control=1(default)にしておく必要がある。

これにより、auto_incrementの際、各ノードで飛び番でauto_incrementの値が払い出される。

sequenceについても、これを設定しておかないと、ノード間で値が重複してしまう。

 

2.create sequence時の設定

wsrep_auto_increment_control=1にした状態で、

以下のようにsequenceをcreateする。

[MariaDB]> CREATE SEQUENCE {シーケンス名} INCREMENT BY 0;

「increment by 0」が重要。

これを行わないと、nextvalの値が各ノードで重複してしまう。

 

実際にGalera3ノードで、wsrep_auto_increment_control=1の状態でnextvalしてみた。

 

・ノード1

[MariaDB]> CREATE SEQUENCE seq01;
[MariaDB]> CREATE SEQUENCE seq02 INCREMENT BY 0;
[MariaDB]> select nextval(seq01);
+----------------+
| nextval(seq01) |
+----------------+
| 1 |
+----------------+

[MariaDB]> select nextval(seq01);
+----------------+
| nextval(seq01) |
+----------------+
| 2 |
+----------------+

[MariaDB]> select nextval(seq02);
+----------------+
| nextval(seq02) |
+----------------+
| 1 |
+----------------+

[MariaDB]> select nextval(seq02);
+----------------+
| nextval(seq02) |
+----------------+
| 4 |
+----------------+

 

・ノード2

[MariaDB]> select nextval(seq01);
+----------------+
| nextval(seq01) |
+----------------+
| 1 |
+----------------+

[MariaDB]> select nextval(seq01);
+----------------+
| nextval(seq01) |
+----------------+
| 2 |
+----------------+

[MariaDB]> select nextval(seq02);
+----------------+
| nextval(seq02) |
+----------------+
| 2 |
+----------------+

[MariaDB]> select nextval(seq02);
+----------------+
| nextval(seq02) |
+----------------+
| 5 |
+----------------+

 

・ノード3

[MariaDB]> select nextval(seq01);
+----------------+
| nextval(seq01) |
+----------------+
| 1 |
+----------------+

[MariaDB]> select nextval(seq01);
+----------------+
| nextval(seq01) |
+----------------+
| 2 |
+----------------+

[MariaDB]> select nextval(seq02);
+----------------+
| nextval(seq02) |
+----------------+
| 3 |
+----------------+

[MariaDB]> select nextval(seq02);
+----------------+
| nextval(seq02) |
+----------------+
| 6 |
+----------------+

 

という結果である。

sequenceはauto_incrementより便利な機能であるが、

galeraで使う場合は注意が必要。

一応、公式に書いてあるが、ちょっと理解するのに手間取った。

https://mariadb.com/kb/en/library/sequence-overview/#replication

 

なお、通常のmaster-slaveレプリケーションでsequenceを利用する場合は、

「auto_increment_increment」「auto_increment_offset」の値によらず、

sequenceのnext_not_cached_valueの値によって、飛び番で発番されるようです。

つまり、slaveの昇格をした場合などは、sequenceの番号が大きく飛ぶ可能性がある。

 

以上

投稿日時:2018年07月25日 13:14   カテゴリー:mariadb   [コメントがあればどうぞ]