カテゴリー「mariadb」

MariaDB10.8.3が2022年5月にGAになりました。

https://mariadb.com/kb/en/mariadb-1083-release-notes/

10.7のときに見落としていたのですが、

10.7も10.8もshort term supportのようで、

サポート期間はリリースから1年のようです。

直近では、10.6がLTSという扱いのようです。

機能概要は以下のとおりです。

https://mariadb.com/kb/en/changes-improvements-in-mariadb-108/

個人的に気になった点だけ挙げておきます。


(LAG free ALTER)

レプリケーションをしていると、ALTER TABLEはまずプライマリ(マスター)で実行され、

完了してはじめて、レプリカ(スレーブ)に伝播するというものでした。

そのため、大きなテーブルでALTERを実行すると、レプリカの遅延が激しくなっていました。

(プライマリでALTER開始〜完了)→レプリケーション→(レプリカでALTER開始〜完了)

って感じが従来の流れですね。

で、今回の機能により、

(プライマリでALTER開始)→レプリケーション→(レプリカでALTER開始)→(プライマリ・レプリカでALTER完了)

って感じになるため、レプリカ遅延、つまりラグがおきにくいですよ、って話かと。

昔MySQLで巨大なテーブルにALTERしたら、マスターで2時間、スレーブで2時間、

合計4時間とかになったことがあったので、

これが合わせて2時間で終わる感じになるので、とても素敵な機能かと思います。

(JSON Histgrams)

histgramの結果を格納しているmysql.column_statsテーブルが変更になりました。

10.4

> desc mysql.column_stats;
+---------------+-----------------------------------------+------+-----+---------+-------+
| Field         | Type                                    | Null | Key | Default | Extra |
+---------------+-----------------------------------------+------+-----+---------+-------+
| db_name       | varchar(64)                             | NO   | PRI | NULL    |       |
| table_name    | varchar(64)                             | NO   | PRI | NULL    |       |
| column_name   | varchar(64)                             | NO   | PRI | NULL    |       |
| min_value     | varbinary(255)                          | YES  |     | NULL    |       |
| max_value     | varbinary(255)                          | YES  |     | NULL    |       |
| nulls_ratio   | decimal(12,4)                           | YES  |     | NULL    |       |
| avg_length    | decimal(12,4)                           | YES  |     | NULL    |       |
| avg_frequency | decimal(12,4)                           | YES  |     | NULL    |       |
| hist_size     | tinyint(3) unsigned                     | YES  |     | NULL    |       |
| hist_type     | enum('SINGLE_PREC_HB','DOUBLE_PREC_HB') | YES  |     | NULL    |       |
| histogram     | varbinary(255)                          | YES  |     | NULL    |       |
+---------------+-----------------------------------------+------+-----+---------+-------+

10.8

> desc mysql.column_stats;
+---------------+---------------------------------------------------+------+-----+---------+-------+
| Field         | Type                                              | Null | Key | Default | Extra |
+---------------+---------------------------------------------------+------+-----+---------+-------+
| db_name       | varchar(64)                                       | NO   | PRI | NULL    |       |
| table_name    | varchar(64)                                       | NO   | PRI | NULL    |       |
| column_name   | varchar(64)                                       | NO   | PRI | NULL    |       |
| min_value     | varbinary(255)                                    | YES  |     | NULL    |       |
| max_value     | varbinary(255)                                    | YES  |     | NULL    |       |
| nulls_ratio   | decimal(12,4)                                     | YES  |     | NULL    |       |
| avg_length    | decimal(12,4)                                     | YES  |     | NULL    |       |
| avg_frequency | decimal(12,4)                                     | YES  |     | NULL    |       |
| hist_size     | tinyint(3) unsigned                               | YES  |     | NULL    |       |
| hist_type     | enum('SINGLE_PREC_HB','DOUBLE_PREC_HB','JSON_HB') | YES  |     | NULL    |       |
| histogram     | longblob                                          | YES  |     | NULL    |       |
+---------------+---------------------------------------------------+------+-----+---------+-------+

hist_typeに「JSON_HB」というものが増えてます。

これにより、「histgram」カラムの値に、JSONとして結果を格納することができるようになります。

で、hist_typeのデフォルトは、「DOUBLE_PREC_HB」のようなので、

「JSON_HB」を使うには以下のようにするようです。

MariaDB [test]> select @@histogram_type;
+------------------+
| @@histogram_type |
+------------------+
| DOUBLE_PREC_HB   |
+------------------+
1 row in set (0.001 sec)

MariaDB [test]> set histogram_type = 'JSON_HB';
Query OK, 0 rows affected (0.001 sec)

MariaDB [test]> select @@histogram_type;
+------------------+
| @@histogram_type |
+------------------+
| JSON_HB          |
+------------------+
1 row in set (0.000 sec)

MariaDB [test]> analyze table user persistent for all;
:
(省略)

そうすると、mysql.column_statsのhistgramカラムにJSONが入るようになります。

長いので一部にしますが、以下のようなJSONが取得入るかと。

MariaDB [test]> select * from mysql.column_stats;
:
{
  "target_histogram_size": 254,
  "collected_at": "2022-06-17 23:23:19",
  "collected_by": "10.8.3-MariaDB-log",
  "histogram_hb": [
    {
      "start": "1",
      "size": 0.00394246,
      "ndv": 689
    },
    {
      "start": "2047",
      "size": 0.00394246,
      "ndv": 689
    },
:
(省略)

なにかに使えるかもしれない。。

(Spider Storage Engine Improvements)

Spider Engineは10.4でプラグイン化しました。

https://mariadb.com/kb/en/spider-installation/

で、今まではSpider用の設定がコメントであったのですが、

これを、以下の3つのシステム変数として定義できるようになったみたいです。

  • REMOTE_SERVER
  • REMOTE_DATABASE
  • REMOTE_TABLE

従来のようにコメントでもできるようです。

これは後日試してみようかと。

(mysqlbinlog GTID support)

「–start-position」と「–stop-position」にGTIDが指定できるようになったようです。

これは嬉しい。

今まで「binlog_gtid_pos」関数使って、ファイルとポジションからGTIDを確認してましたが、

わざわざそんなことをしなくていいとなると、細かいようですが、かなりいいかなと。

ちなみに、MariaDBはGTIDを使ってレプリケーションを組むと、crash safeです。

ファイルとポジションはcrash unsafeです。

MySQLでは、

relay_log_info_repository = table

とすることで、crash safeにしていたかと。(MySQL8で、この辺もInnoDBになったはず)


という感じですかね。

Spiderとmariadb-binlog(mysql-binlog)は、後日検証しようかと思います。

また、私が作っているmagentadeskも、v0.4.5で10.8に対応しました。

https://github.com/shigenobu/magentadesk

以上

投稿日時:2022年06月17日 23:52   カテゴリー:mariadb   [コメントがあればどうぞ]

アプリケーションで長々SQLを書かなきゃいけないんだけど、

条件によってはSQLを評価しないときってあるかと思います。

たとえば、検索するときの対象テーブルとして、

  • 記事
  • 動画

の2つがあったとき、条件によっては、記事のみにしたいって場合です。

このとき、アプリケーションのIFで、動画のSQLは流さないようにするってのが普通だと思うんですが、

CTE(WITH)とか使っていると、後続の式(たとえばUNION)で動画の分を抜くとか調整しなくちゃいけなくてめんどくさかったり。。

そんなとき、ちょっと役に立つ技が「LIMIT 0」です。

これは、公式にも書いてあるように、即座に空の結果セットを返すというものです。

https://dev.mysql.com/doc/refman/8.0/ja/limit-optimization.html

explain時のExtraには、「Zero limit」というのが表示されます。

それ以外にも、SQLとして正しいかどうかだけをチェックするときにも使えたりします。

「LIMIT 0」以外にも、自分の小ネタを紹介しておきます。

たとえば、アプリケーションでWHEREを組み立てなきゃいけないとき、

条件がなにもなかったら、WHERE句自体を消すとかもありますよね。

そんなとき、自分は「1 = 1」で初期化しておくみたいなこともやったりします。

そうすると、WHERE句自体は残したままでよくなるので、文字列編集の煩わしさが減ります。

「LIMIT 0」とか「WHERE 1 = 1」とか、はっきいって邪道ですが、

使うと意外にアプリケーションでのSQL構築が楽になったりします。

以上

投稿日時:2022年05月10日 00:07   カテゴリー:mariadb, mysql   [コメントがあればどうぞ]

1対Nのテーブル2つがある場合、N側のテーブルはデータを縦持ちするはず。

しかしながら、1側のテーブルに合わせて、1行で表示したい場合の小ネタ。

せっかくなので、MariaDB10.7の新機能も添えて紹介。


たとえば、こんなテーブルとデータがあります。

CREATE TABLE `question` (
  `question_id` int(11) NOT NULL COMMENT '問題ID',
  `question_text` text NOT NULL COMMENT '本文',
  PRIMARY KEY (`question_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='問題'

> select * from question;
+-------------+--------------------------------------------------------------------------------------------------------------+
| question_id | question_text                                                                                                |
+-------------+--------------------------------------------------------------------------------------------------------------+
|           1 | しゃっくりはある調味料をなめると止まります。ある調味料とはなんでしょう?                                                 |
+-------------+--------------------------------------------------------------------------------------------------------------+
CREATE TABLE `question_select` (
  `question_id` int(11) NOT NULL COMMENT '問題ID',
  `select_id` int(11) NOT NULL COMMENT '選択肢ID',
  `select_text` text NOT NULL COMMENT '選択肢内容',
  PRIMARY KEY (`question_id`,`select_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='選択肢'

> select * from question_select;
+-------------+-----------+-------------+
| question_id | select_id | select_text |
+-------------+-----------+-------------+
|           1 |         1 | お酢        |
|           1 |         2 | 砂糖        |
|           1 |         3 | 醤油        |
|           1 |         4 | 塩          |
+-------------+-----------+-------------+

これを1行で表示したい場合、以下のようにやる。

> with 
 t as (
   select
     t1.question_id,
     t1.question_text,
     sformat('[{}]', group_concat(distinct json_object('select_id', t2.select_id, 'select_text', t2.select_text) order by t2.select_id)) as select_list
   from
     question as t1
     join
     question_select as t2
     on t1.question_id = t2.question_id
   group by
     t1.question_id, t1.question_text
 )
 select
   question_id,
   question_text,
   json_value(select_list, '$[0].select_id') as select_id_1,
   json_value(select_list, '$[0].select_text') as select_text_1,
   json_value(select_list, '$[1].select_id') as select_id_2,
   json_value(select_list, '$[1].select_text') as select_text_2,
   json_value(select_list, '$[2].select_id') as select_id_3,
   json_value(select_list, '$[2].select_text') as select_text_3,
   json_value(select_list, '$[3].select_id') as select_id_4,
   json_value(select_list, '$[3].select_text') as select_text_4
 from
   t
 ;
+-------------+--------------------------------------------------------------------------------------------------------------+-------------+---------------+-------------+---------------+-------------+---------------+-------------+---------------+
| question_id | question_text                                                                                                | select_id_1 | select_text_1 | select_id_2 | select_text_2 | select_id_3 | select_text_3 | select_id_4 | select_text_4 |
+-------------+--------------------------------------------------------------------------------------------------------------+-------------+---------------+-------------+---------------+-------------+---------------+-------------+---------------+
|           1 | しゃっくりはある調味料をなめると止まります。ある調味料とはなんでしょう?                                                 | 1           | お酢          | 2           | 砂糖          | 3           | 醤油          | 4           | 塩            |
+-------------+--------------------------------------------------------------------------------------------------------------+-------------+---------------+-------------+---------------+-------------+---------------+-------------+---------------+

ポイントはgroup_concatで横持ちに変換する際に、JSON配列にしてしまうこと。

集計するときに結構使える技。

今回はMariaDBの10.7新機能であるsformat関数を使ってみましたが、concat関数でも代用可能です。

MySQLの場合は、「->>」とかで、JSONから値を取り出す感じですかね。

以上

投稿日時:2022年02月22日 18:33   カテゴリー:mariadb, mysql   [コメントがあればどうぞ]

MariaDB10.7が2022年2月にGAとなりました。10.6から8ヶ月スパンでのリリースです。

https://mariadb.com/kb/en/changes-improvements-in-mariadb-107/

10.7.2はmysql_upgradeに不具合があり、すぐにリリースが取り消され、

10.7.3が初回GAとなったようです。

公式に書いてありますが、個人的に気になった点をまとめておきます。

  • UUID型(UUID DATA TYPE)の追加および、UUID系関数追加
  • JSON関数追加
  • order by時のオプションとして、「natural_sort_key」が追加
  • optimizer switchに「reorder」追加(デフォルトOFFのようです)
  • エンジン非依存の圧縮機能をプラグインとして追加(デフォルトのzlib以外はmysql_upgradeのときは注意が必要)
  • sformat関数追加(pythonのformat関数みたい)
  • mariadb-dumpの際、–as-ofオプションで、特定の瞬間のsystem versionedテーブルの状態を取得できる(全履歴じゃないので要注意)

あとは公式に書いてあるとおりです。

個人的には、sformat関数は嬉しいかなと。

結構、concat関数をつなげてることが多く、どうも見づらいなーと思っていたので。

あと、自分が作っているmagentadeskも、

UUID型と10.5で追加されたINET6型の対応も含めて、

10.7対応版としてv0.4.4をリリースしました。

https://github.com/shigenobu/magentadesk

10.8もすでにRCが動いているようで、10.8が早く来そうです。

10.8の対応内容は結構すごい感じを受けます。期待ですね。

以上

投稿日時:2022年02月22日 18:01   カテゴリー:mariadb   [コメントがあればどうぞ]

個人でこっそりgithubで作っているMariaDBの差分検出・反映ツールである「magentadesk」に、

API機能とHTML機能を追加しました。(0.4.0からHTML機能がはいってます)

(magentadesk)

https://github.com/shigenobu/magentadesk

今まではcli版しかなったのですが、web版も追加されています。

web版でしていることは、cli版の処理を呼び出しているに過ぎないのですが、

HTML機能を使うことで、各種jsonデータをsqliteに保存しておけるようになり、ボタン一つで差分検出・反映が可能となります。

API機能は、cli版の単なるHTTPインターフェースでしかないのですが、

HTML機能で追加したrelationという設定は、テーブルの子・親関係を登録しておくことで、

差分検出時にチェックボックスが連動するというものとなります。

magantadeskでは、外部キーが設定されているものは、

反映対象外としている(これは反映順番の整合性を保つのが難しいため)のですが、

それだと、差分確認時に、親子関係がわかりくいということから、このような機能を作ってみました。

で、API・HTML機能を作るに当たり、苦労した点があったので書いておきます。


(HTTPサーバにcom.sun.net.httpserver.HttpServerを利用)

デフォルトで同胞されているHTTPサーバなのですが、これが非常にくせのあるものでした。

例外などの際、ようは最後の最後のタイミングで、ただしくHTTPレスポンスを構築してくれないので、

最後の最後で、レスポンスを構築するように工夫しました。

(HTML機能の情報を蓄積するDBとして、sqliteを利用)

READ-COMMITEDをサポートしていないので、SERIALIZABLEの分離レベルを選択。

そのうえで、ファイルのため、WRITEブロックをすることは明白なので、

とにかくsqliteに接続している時間を各処理で短くするよう調整しました。

(テンプレートエンジンとしてvelocityを利用)

え?veloctiy?と思うかもしれませんが、2.3というバージョンが出ています。

当方は、velocity-toolは使わず、

event_handler.reference_insertion.class(旧eventhandler.referenceinsertion.class)

のプロパティを設定して、独自クラスでテンプレート関数を追加しています。

テンプレート上で、NULLと空文字の判定がデフォルトではできなかったので、

独自関数で対応しました。


という具合に、地道な苦労を重ねました。

magentadeskは主にwebサービスでの本番反映を想定して、汎用化を試みたものですが、

ニーズは少なそうだなと感じています。。

今後は、国際化対応(日本語化)を入れていきたいかなと考えていますが、

JAVAではなく、jqueryでやろうかなとか考え中です。

以上

投稿日時:2021年11月25日 15:04   カテゴリー:java, mariadb   [コメントがあればどうぞ]

またMySQLのUDFをつくってみた。

https://github.com/shigenobu/mysql_ws_neologd_normalize

今回は有名なneologdの標準化アルゴリズムに、CR・LF・タブ・水平タブを削除するものを追加したUDFです。

(参考 neologdの標準化アルゴリズム)

https://github.com/neologd/mecab-ipadic-neologd/wiki/Regexp.ja

なぜこれを作ったかというと、すべては検索のためですね。

入力も、対象データも、そして辞書すらも、すべて一定のアルゴリズムで標準化されることで、

正しく検索が機能するためです。

今回のUDFは、対象データの部分に該当します。

入力の部分は、C#とPHPでも同様のアルゴリズムを実装していますが、

そこまで大したものではないので、特に公開はしてないです。

※さらにいえば、入力の部分では、対象データと同じアルゴリズムの形態素解析も必要かなと思います。

だいぶ、cgoでMySQLのUDFを作ってきた(現在5つをgithubに公開)のですが、

今後はrustとかに手を出して、redisモジュールなんかもつくってみたいかと(自分の中で需要がないが。。)。

今回のUDFは、すでに長いこと実践投入しているので、多分大丈夫だと思います。

いや、他のUDFが不具合ありって、いうわけじゃないですけど。

以上

投稿日時:2021年10月05日 23:40   カテゴリー:go, mariadb, mysql   [コメントがあればどうぞ]

Mysql/MariaDBのsubstring関数は、マルチバイトセーフと書いてあります。

しかしながら、日本語の長文を扱っている際、JDBCおよびADO.NETからsubstringするとなぜか、

Incorrect string value:

のエラーが出てしまいました。

文字コードや各接続はutf8mb4で統一しており、どうもおかしいと思い、原因は不明なままでしたが、

例によってcgoで作ってみました。

https://github.com/shigenobu/mysql_ws_substring

この関数を通すことで、上記エラーは発生しなくなりました。

あまりに長文だったのですが、utf8の不正なバイトシーケンスが入っていたのでは?と思っていますが、

さすがに根気がなくなり調査断念しました。(それに急ぎだったので)

まあ、なんでこんな関数つくったのかというと、mroongaを使っていた際、

mecab_sparse_tostr() failed len=xxxxx err=too long sentence

のエラーが出てしまい、自作のwordwrap関数でもこの問題は解決せず、

「あれ、ひょっとして文書が長過ぎる?」と思い、データを見てみたところ、

どうも256KiBを超えたあたりが怪しい感じがしました。

というわけで、10万文字でsubstringしてINSERTできればOKじゃね?と思い、

この関数を作ってみました。

結果として、10万文字に収めたところ、上記エラーはでなくなりました。

mroongaの公式サイトには、

GRN_MECAB_CHUNKED_TOKENIZE_ENABLED=yes

の環境変数を利用することで、解決するかもと書いてあって試してみたものの、

当該カラムの文書量が多いせいか、2時間以上たっても、FULL TEXT インデックスが構築完了しませんでした。

※文書が少ないカラムはこちらの環境変数を設定していても即座にインデックスの構築は完了しました。

一度でも登録したらエラーとなっているので、今回の関数でいかざるを得なかった感じです。

時間があったら、mecabのソースなどを調査してみようと思います。

以上

投稿日時:2021年10月01日 00:28   カテゴリー:go, mariadb, mysql   [コメントがあればどうぞ]

PHPのwordwrap関数のマルチバイト対応版をMySQLのUDFとしてつくりました。

いつものようにcgoで作ってます。

https://github.com/shigenobu/mysql_ws_wordwrap

PHPのwordwrap関数は以下のリンクとなります。

(PHPのwordwrap)

https://www.php.net/manual/ja/function.wordwrap.php

今回作ったUDFのポイントは、なるべくPHPの関数の第4引数(cut_long_words)をtrueの状態にしたものとなります。

で、このPHPのwordwrap関数の特徴として、何度やっても同じになる(微妙な表現ですが)になるってことなのかと思います。

php > $input = 'aa<br>abbbccc<br>dddee<br>e';
php > $dst1 = wordwrap($input, 3, '<br>', true);
php > echo $dst1;
aa<br>abb<br>bcc<br>c<br>ddd<br>ee<br>e
php > $dst2 = wordwrap($dst1, 3, '<br>', true);
php > echo $dst2;
aa<br>abb<br>bcc<br>c<br>ddd<br>ee<br>e
php > echo (int) $dst1 == $dst2;
1

つまり、breakワードが分割位置に含まれていたら、そこで分割せずに、breakワードを残しつつ、次以降の文字列の評価を行うものなのかと。

※なんていうアルゴリズムなのかわからなかったので、正解ではないかもしれません。

作り始めた当初は、breakワードを一旦消してから、指定文字数でbreakワードいれればいける?と思っていたのですが、

もとの文章にbreakワードが入っている場合、それを消してしまうことになるので、それはちょっと違うかなと思い、

breakワードの位置を探しつつ、構築する形にしてみました。

なんでこんな関数を作ったのかというと、mroongaを使っていた際、

mecab_sparse_tostr() failed len=xxxxx err=too long sentence

というエラーがでたので、これってmecabのストップワードがないから?と思ってしまい、

それなら強制的にwordwrapさせればいける?と思い、作りました。

実際には、文書自体が長過ぎるとエラーになるようで、この関数では解決しなかったんですが。。

本来ならストップワードを指定して分割する形も考えたのですが、急ぎで対応する必要があったので、

今後ヒマがあったら考えみようかと思います。

以上

投稿日時:2021年10月01日 00:02   カテゴリー:go, mariadb, mysql   [コメントがあればどうぞ]

MariaDB 10.6が7月にGAになっていました。

https://mariadb.com/kb/en/changes-improvements-in-mariadb-106/

ざっくり変更点。(ざっくりだよ)

  • Atomic DDL が入った模様
  • SKIP LOCKEDが入った模様(MySQL8に追従ですね)
  • ignored index(MySQLでいうとinvisbile index)
  • json_table関数(ここもMySQL8に追従ですね)
  • sysスキーマ
  • utf8mb3の導入
  • innodbのパラメータが結構削除

と言った形で、利用者向けには、MySQL8への追従が結構ある感じです。(Oracleの関数対応もありますが)

管理者向けには、innodb関係のパラメータ削除(10.4でdeprecatedになっていたが)は気をつけるべきかと。

まだ全然試せていませんが、utf8がなくなっている(DDLではutf8でOKだが、information_schemaではutf8mb3になっている)ので、

ちょっと注意が必要。(わたしがつくっているmagentadeskも10.6には対応済み)

そのほか、気になっているのが、10.5.9くらい(10.4系の新しいのも)で、log_write_up_toの改修が入ったようなのですが、

10.6系も引き続き入っており、このあたりがどうなっているかはちょっとテストしてみないとわからん感じです。

以上

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

10.2からバイナリログを逆さにするflashbackという機能が追加されたのですが、中々実践でためす機会もなかったので、改めて動きを確認してみます。

確認したバージョンは、10.5.5です。


(前提)

以下のようなテーブルを作成し、データと投入します。

MariaDB [test]> show create table fb;
+-------+-----------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+-----------------------------------------------------------------------------------------------------------------------------------+
| fb | CREATE TABLE fb (
no int(11) NOT NULL,
name text NOT NULL,
PRIMARY KEY (no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 |
+-------+-----------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)

MariaDB [test]> insert into fb value (1, 'あああ');
Query OK, 1 row affected (0.003 sec)

MariaDB [test]> select * from fb;
+----+-----------+
| no | name |
+----+-----------+
| 1 | あああ |
+----+-----------+
1 row in set (0.001 sec)

GTIDとバイナリログを確認します。

MariaDB [test]> show variables like 'gtid_binlog_pos';
+-------------------------+------------+
| Variable_name | Value |
+-------------------------+------------+
| gtid_binlog_pos | 0-1-284795 |
+-------------------------+------------+
1 rows in set (0.001 sec)

MariaDB [test]> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000066 | 54405979 |
| mysql-bin.000067 | 9650 |
| mysql-bin.000068 | 2667 |
+------------------+-----------+
3 rows in set (0.000 sec)

わかりやすくするために、一度バイナリログをflushします。

MariaDB [test]> flush binary logs;
Query OK, 0 rows affected (0.005 sec)

MariaDB [test]> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000066 | 54405979 |
| mysql-bin.000067 | 9650 |
| mysql-bin.000068 | 2714 |
| mysql-bin.000069 | 385 |
+------------------+-----------+
4 rows in set (0.000 sec)

一応、GTID確認します。

MariaDB [test]> show variables like 'gtid_binlog_pos';
+-------------------------+------------+
| Variable_name | Value |
+-------------------------+------------+
| gtid_binlog_pos | 0-1-284795 |
+-------------------------+------------+
1 rows in set (0.001 sec)

GTIDは「0-1-284795」のままですね。

(データ追加)

データを追加し、GTIDを確認します。

MariaDB [test]> insert into fb value (2, 'いいい');
Query OK, 1 row affected (0.003 sec)

MariaDB [test]> select * from fb;
+----+-----------+
| no | name |
+----+-----------+
| 1 | あああ |
| 2 | いいい |
+----+-----------+
2 rows in set (0.000 sec)

MariaDB [test]> show variables like 'gtid_binlog_pos';
+-------------------------+------------+
| Variable_name | Value |
+-------------------------+------------+
| gtid_binlog_pos | 0-1-284796 |
+-------------------------+------------+
1 rows in set (0.001 sec)

GTIDが「0-1-284796」に変わりました。ここで、バイナリログを見てみます。長いので、一部だけにします。

# mysqlbinlog --no-defaults -vvv /var/lib/mysql/mysql-bin.000069
:
:
# at 256
#210224 11:08:36 server id 1  end_log_pos 299 CRC32 0xacff8998 	Gtid list [0-1-284795]
# at 299
#210224 11:08:36 server id 1  end_log_pos 342 CRC32 0x8bf7cf8a 	Binlog checkpoint mysql-bin.000068
# at 342
#210224 11:08:36 server id 1  end_log_pos 385 CRC32 0x187e7066 	Binlog checkpoint mysql-bin.000069
# at 385
#210224 11:09:30 server id 1  end_log_pos 427 CRC32 0x5386bf8e 	GTID 0-1-284796 trans
/*!100101 SET @@session.skip_parallel_replication=0*//*!*/;
/*!100001 SET @@session.gtid_domain_id=0*//*!*/;
/*!100001 SET @@session.server_id=1*//*!*/;
/*!100001 SET @@session.gtid_seq_no=284796*//*!*/;
START TRANSACTION
/*!*/;
# at 427
# at 487
#210224 11:09:30 server id 1  end_log_pos 487 CRC32 0x685176b0 	Annotate_rows:
#Q> insert into fb value (2, 'いいい')
#210224 11:09:30 server id 1  end_log_pos 534 CRC32 0x02e81a93 	Table_map: `test`.`fb` mapped to number 64
# at 534
#210224 11:09:30 server id 1  end_log_pos 583 CRC32 0x9a15a3b4 	Write_rows: table id 64 flags: STMT_END_F

BINLOG '
WrU1YBMBAAAALwAAABYCAAAAAEAAAAAAAAEABHRlc3QAAmZiAAID/AECAJMa6AI=
WrU1YBcBAAAAMQAAAEcCAAAAAEAAAAAAAAEAAv/8AgAAAAkA44GE44GE44GEtKMVmg==
'/*!*/;
### INSERT INTO `test`.`fb`
### SET
###   @1=2 /* INT meta=0 nullable=0 is_null=0 */
###   @2='いいい' /* BLOB/TEXT meta=2 nullable=0 is_null=0 */
# Number of rows: 1
# at 583
#210224 11:09:30 server id 1  end_log_pos 614 CRC32 0x2ae1c8a4 	Xid = 4087358
COMMIT/*!*/;
DELIMITER ;
:
:

まずは、「# at 256」を見てみます。

# at 256
#210224 11:08:36 server id 1  end_log_pos 299 CRC32 0xacff8998 	Gtid list [0-1-284795]

listされたGTIDが「0-1-284795」になっているので、ここが直前のGTIDであり、

insert into fb value (1, 'あああ');

の直後となっています。

念の為、確認します。

MariaDB [test]> select binlog_gtid_pos('mysql-bin.000069', 256);
+------------------------------------------+
| binlog_gtid_pos('mysql-bin.000069', 256) |
+------------------------------------------+
| 0-1-284795 |
+------------------------------------------+
1 row in set (0.001 sec)

次に、「# at 385」を見てみます。

# at 385
#210224 11:09:30 server id 1 end_log_pos 427 CRC32 0x5386bf8e GTID 0-1-284796 trans

385からが、次のGTIDの開始点となります。そこから直近のCOMMITまでを追っていくと、

# at 583
#210224 11:09:30 server id 1  end_log_pos 614 CRC32 0x2ae1c8a4 	Xid = 4087358
COMMIT/*!*/;

583に辿り着きます。583のGTIDを確認します。

MariaDB [test]> select binlog_gtid_pos('mysql-bin.000069', 583);
+------------------------------------------+
| binlog_gtid_pos('mysql-bin.000069', 583) |
+------------------------------------------+
| 0-1-284796 |
+------------------------------------------+
1 row in set (0.001 sec)

ここまでを整理すると、

GTID:「0-1-284795」(ポジション:「256」)は「(1, ‘あああ’)」の直後、

GTID:「0-1-284796」(ポジション:「583」)は「(2, ‘いいい’)」の直後、

となります。

※正確には、256を示すend_log_posのatが、1つ前のポジションです。

(操作取消)

では、GTID:「0-1-284796」の操作を取り消します。

# mysqlbinlog --no-defaults -vvv /var/lib/mysql/mysql-bin.000069 --start-position=256 --stop-position=583 --flashback 
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
#210224 11:08:36 server id 1  end_log_pos 256 CRC32 0x9b36958f 	Start: binlog v 4, server v 10.5.5-MariaDB-log created 210224 11:08:36
# Warning: this binlog is either in use or was not closed properly.
BINLOG '
JLU1YA8BAAAA/AAAAAABAAABAAQAMTAuNS41LU1hcmlhREItbG9nAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAA5AAEGggAAAAICAgCAAAACgoKAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAEEwQADQgICAoKCgGPlTab
'/*!*/;
#210224 11:08:36 server id 1  end_log_pos 299 CRC32 0xacff8998 	Gtid list [0-1-284795]
#210224 11:08:36 server id 1  end_log_pos 342 CRC32 0x8bf7cf8a 	Binlog checkpoint mysql-bin.000068
#210224 11:08:36 server id 1  end_log_pos 385 CRC32 0x187e7066 	Binlog checkpoint mysql-bin.000069
#210224 11:09:30 server id 1  end_log_pos 487 CRC32 0x685176b0 	Annotate_rows:
#Q> insert into fb value (2, 'いいい')
#210224 11:09:30 server id 1  end_log_pos 534 CRC32 0x02e81a93 	Table_map: `test`.`fb` mapped to number 64
# Number of rows: 1
#210224 11:09:30 server id 1  end_log_pos 583 CRC32 0x9a15a3b4 	Delete_rows: table id 64 flags: STMT_END_F

BINLOG '
WrU1YBMBAAAALwAAABYCAAAAAEAAAAAAAAEABHRlc3QAAmZiAAID/AECAJMa6AI=
WrU1YBkBAAAAMQAAAEcCAAAAAEAAAAAAAAEAAv/8AgAAAAkA44GE44GE44GEtKMVmg==
'/*!*/;
### DELETE FROM `test`.`fb`
### WHERE
###   @1=2 /* INT meta=0 nullable=0 is_null=0 */
###   @2='いいい' /* BLOB/TEXT meta=2 nullable=0 is_null=0 */
COMMIT
/*!*/;
COMMIT
/*!*/;
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

これをファイルに落として、実行することで、「(2, ‘いいい’)」のINSERTが取り消されます。ただし、バイナリログには、別途GTIDが切り出されます。

長くなりましたが、

start-positionの部分には、”戻したい場所”にしましょう。

今回では、

Gtid list [0-1-284795]

の箇所が直前のGTID払い出し位置となるので、ここに戻すようにしています。

MariaDBだと、GTIDで状態を確認することが多いので、flashbackでもGTIDの状態をみるように注意して対応してみました。

以上

投稿日時:2021年02月24日 13:50   カテゴリー:mariadb   [コメントがあればどうぞ]