GA

2022/07/21

MySQLのシノニムではないけど同じような動きをする何か(と、SHOW SLAVE STATUSとSHOW REPLICA STATUSの地味な違い)

TL;DR


実装上はシノニムになっていないけれど、同じ(ような)動きをする何かたち。

その1 その2 扱い
MASTER, SLAVE系 SOURCE, REPLICA系 sql/sql_yacc.yyの中で丸められている
{SHOW|PURGE} BINARY LOGS {SHOW|PURGE} MASTER LOGS 同上
SERIAL BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PT_serial_type の中で BIGINT UNSIGNED NOT NULL AUTO_INCREMENT属性に上書きしてる
複合SQLモード expand_sql_mode の中でベースのsql_modeの羅列に展開
repl_semi_sync_{master|slave} repl_semi_sync_{source|replica} 実は違う.soファイル(ソースはほぼ一緒)
$ ll /usr/mysql/8.0.29/lib/plugin/*semi*
-rwxr-xr-x 1 yoku0825 yoku0825 239040 Apr 26 20:08 /usr/mysql/8.0.29/lib/plugin/semisync_master.so
-rwxr-xr-x 1 yoku0825 yoku0825  79896 Apr 26 20:08 /usr/mysql/8.0.29/lib/plugin/semisync_replica.so
-rwxr-xr-x 1 yoku0825 yoku0825  80696 Apr 26 20:08 /usr/mysql/8.0.29/lib/plugin/semisync_slave.so
-rwxr-xr-x 1 yoku0825 yoku0825 238136 Apr 26 20:08 /usr/mysql/8.0.29/lib/plugin/semisync_source.so

$ ll ~/mysql-8.0.plugin/semisync/*.cc
-rw-r--r-- 1 yoku0825 yoku0825  2306 Mar 23 22:52 plugin/semisync/semisync.cc
-rw-r--r-- 1 yoku0825 yoku0825  5416 Mar 23 22:52 plugin/semisync/semisync_replica.cc
-rw-r--r-- 1 yoku0825 yoku0825 12620 Mar 23 22:52 plugin/semisync/semisync_replica_plugin.cc
-rw-r--r-- 1 yoku0825 yoku0825  1218 Mar 23 22:52 plugin/semisync/semisync_replica_plugin_old.cc
-rw-r--r-- 1 yoku0825 yoku0825 42647 Mar 23 22:52 plugin/semisync/semisync_source.cc
-rw-r--r-- 1 yoku0825 yoku0825 10554 Mar 23 22:52 plugin/semisync/semisync_source_ack_receiver.cc
-rw-r--r-- 1 yoku0825 yoku0825 28669 Mar 23 22:52 plugin/semisync/semisync_source_plugin.cc
-rw-r--r-- 1 yoku0825 yoku0825  1217 Mar 23 22:52 plugin/semisync/semisync_source_plugin_old.cc

他に何かあったっけなあ…? あったら教えてください :bow:


おまけ。

丸められているは丸められているんだけど、 SHOW SLAVE STATUSSHOW REPLICA STATUS は互換性のために「どちらのステートメントで呼ばれたか」によって返すカラムの名前を正規表現で置換していて、 SHOW SLAVE STATUS の方を使ってしまうとCPUオーバーヘッドが乗るらしい。

slave1 [localhost] {msandbox} ((none)) > SHOW SLAVE STATUS\G
               Slave_IO_State: Waiting for source to send event
             Slave_IO_Running: Yes
                Last_IO_Errno: 0
                Last_IO_Error:
      Last_IO_Error_Timestamp:
1 row in set, 1 warning (0.00 sec)

slave1 [localhost] {msandbox} ((none)) > SHOW REPLICA STATUS\G
             Replica_IO_State: Waiting for source to send event
           Replica_IO_Running: Yes
                Last_IO_Errno: 0
                Last_IO_Error:
      Last_IO_Error_Timestamp:
1 row in set (0.00 sec)

2022/07/20

xtrabackup 8.0.29とINSTANT COLUMNと

 

TL;DR


 $ xtrabackup --version

2022-07-20T18:36:05.410933+09:00 0 [Note] [MY-011825] [Xtrabackup] recognized server arguments: --server-id=1 --log_bin=mysql-bin --log-bin-index=bin.index --innodb_buffer_pool_size=60G --innodb_file_per_table=1 --innodb_flush_method=O_DIRECT

xtrabackup version 8.0.29-22 based on MySQL server 8.0.29 Linux (x86_64) (revision id: c31e7ddcce3)

INSTANT COLUMNが無ければ、Vanilla MySQL 8.0.29のバックアップが取れる。

$ xtrabackup -S /usr/mysql/8.0.29/data/mysql.sock -uroot --backup
2022-07-20T18:39:23.707951+09:00 0 [Note] [MY-011825] [Xtrabackup] recognized server arguments: --server-id=1 --log_bin=mysql-bin --log-bin-index=bin.index --innodb_buffer_pool_size=60G --innodb_file_per_table=1 --innodb_flush_method=O_DIRECT
2022-07-20T18:39:23.708199+09:00 0 [Note] [MY-011825] [Xtrabackup] recognized client arguments: --user=root --socket=/usr/mysql/8.0.29/data/mysql.sock --user=root --backup=1
xtrabackup version 8.0.29-22 based on MySQL server 8.0.29 Linux (x86_64) (revision id: c31e7ddcce3)
220720 18:39:23  version_check Connecting to MySQL server with DSN 'dbi:mysql:;mysql_read_default_group=xtrabackup;mysql_socket=/usr/mysql/8.0.29/data/mysql.sock' as 'root'  (using password: NO).
220720 18:39:23  version_check Connected to MySQL server
220720 18:39:23  version_check Executing a version check against the server...
220720 18:39:23  version_check Done.
2022-07-20T18:39:23.807722+09:00 0 [Note] [MY-011825] [Xtrabackup] Connecting to MySQL server host: localhost, user: root, password: not set, port: not set, socket: /usr/mysql/8.0.29/data/mysql.sock
2022-07-20T18:39:23.812076+09:00 0 [Note] [MY-011825] [Xtrabackup] Using server version 8.0.29
2022-07-20T18:39:23.815319+09:00 0 [Note] [MY-011825] [Xtrabackup] Executing LOCK INSTANCE FOR BACKUP ...
2022-07-20T18:39:23.818088+09:00 0 [Note] [MY-011825] [Xtrabackup] uses posix_fadvise().
2022-07-20T18:39:23.818165+09:00 0 [Note] [MY-011825] [Xtrabackup] cd to /usr/mysql/8.0.29/data/
2022-07-20T18:39:23.818196+09:00 0 [Note] [MY-011825] [Xtrabackup] open files limit requested 0, set to 81920
2022-07-20T18:39:23.818276+09:00 0 [Note] [MY-011825] [Xtrabackup] using the following InnoDB configuration:
2022-07-20T18:39:23.818297+09:00 0 [Note] [MY-011825] [Xtrabackup] innodb_data_home_dir = .
2022-07-20T18:39:23.818312+09:00 0 [Note] [MY-011825] [Xtrabackup] innodb_data_file_path = ibdata1:12M:autoextend

..

2022-07-20T18:39:34.555754+09:00 0 [Note] [MY-011825] [Xtrabackup] Executing FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS...
2022-07-20T18:39:34.557365+09:00 0 [Note] [MY-011825] [Xtrabackup] The latest check point (for incremental): '32821155948'
2022-07-20T18:39:34.557413+09:00 0 [Note] [MY-011825] [Xtrabackup] Stopping log copying thread at LSN 32821156733
2022-07-20T18:39:34.557518+09:00 1 [Note] [MY-011825] [Xtrabackup] Starting to parse redo log at lsn = 32821155894
2022-07-20T18:39:34.557794+09:00 1 [Note] [MY-011825] [Xtrabackup] >> log scanned up to (32821156812)
2022-07-20T18:39:35.559968+09:00 0 [Note] [MY-011825] [Xtrabackup] Executing UNLOCK INSTANCE
2022-07-20T18:39:35.560323+09:00 0 [Note] [MY-011825] [Xtrabackup] All tables unlocked
2022-07-20T18:39:35.560364+09:00 0 [Note] [MY-011825] [Xtrabackup] Backup created in directory '/home/yoku0825/xtrabackup_backupfiles/'
2022-07-20T18:39:35.560378+09:00 0 [Note] [MY-011825] [Xtrabackup] MySQL binlog position: filename 'mysql-bin.000120', position '197', GTID of the last change '9079d03d-dcd3-11ec-8628-fa163f8f0da3:1-198063'
2022-07-20T18:39:35.560505+09:00 0 [Note] [MY-011825] [Xtrabackup] Writing /home/yoku0825/xtrabackup_backupfiles/backup-my.cnf
2022-07-20T18:39:35.560576+09:00 0 [Note] [MY-011825] [Xtrabackup] Done: Writing file /home/yoku0825/xtrabackup_backupfiles/backup-my.cnf
2022-07-20T18:39:35.561428+09:00 0 [Note] [MY-011825] [Xtrabackup] Writing /home/yoku0825/xtrabackup_backupfiles/xtrabackup_info
2022-07-20T18:39:35.561513+09:00 0 [Note] [MY-011825] [Xtrabackup] Done: Writing file /home/yoku0825/xtrabackup_backupfiles/xtrabackup_info
2022-07-20T18:39:36.562474+09:00 0 [Note] [MY-011825] [Xtrabackup] Transaction log of lsn (32821155948) to (32821156822) was copied.
2022-07-20T18:39:36.781992+09:00 0 [Note] [MY-011825] [Xtrabackup] completed OK!

いつの間にかxbも MY- の番号つけるようになっていたのね(何か親近感を感じる番号だ)

フツーにバックアップは取れたので、INSTANT COLUMNを足してみる。

$ mysql80 d1
mysql80 86> SHOW CREATE TABLE t1\G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `num` bigint unsigned NOT NULL AUTO_INCREMENT,
  `val` varchar(32) COLLATE utf8mb4_ja_0900_as_cs DEFAULT NULL,
  UNIQUE KEY `num` (`num`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_ja_0900_as_cs
1 row in set (0.01 sec)

mysql80 86> ALTER TABLE t1 ADD col INT;  -- ALGORITHM=INSTANTを省略してもINSTANT ADD COLUMNになる
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql80 86> SELECT * FROM information_schema.INNODB_TABLES WHERE total_row_versions > 0;
+----------+-------+------+--------+-------+------------+---------------+------------+--------------+--------------------+
| TABLE_ID | NAME  | FLAG | N_COLS | SPACE | ROW_FORMAT | ZIP_PAGE_SIZE | SPACE_TYPE | INSTANT_COLS | TOTAL_ROW_VERSIONS |
+----------+-------+------+--------+-------+------------+---------------+------------+--------------+--------------------+
|    22441 | d1/t1 |   33 |      6 | 21380 | Dynamic    |             0 | Single     |            0 |                  1 |
+----------+-------+------+--------+-------+------------+---------------+------------+--------------+--------------------+
1 row in set (0.01 sec)
$ rm -r xtrabackup_backupfiles/

$ xtrabackup -S /usr/mysql/8.0.29/data/mysql.sock -uroot --backup
2022-07-20T18:43:20.923483+09:00 0 [Note] [MY-011825] [Xtrabackup] recognized server arguments: --server-id=1 --log_bin=mysql-bin --log-bin-index=bin.index --innodb_buffer_pool_size=60G --innodb_file_per_table=1 --innodb_flush_method=O_DIRECT
2022-07-20T18:43:20.923747+09:00 0 [Note] [MY-011825] [Xtrabackup] recognized client arguments: --user=root --socket=/usr/mysql/8.0.29/data/mysql.sock --user=root --backup=1
xtrabackup version 8.0.29-22 based on MySQL server 8.0.29 Linux (x86_64) (revision id: c31e7ddcce3)
220720 18:43:21  version_check Connecting to MySQL server with DSN 'dbi:mysql:;mysql_read_default_group=xtrabackup;mysql_socket=/usr/mysql/8.0.29/data/mysql.sock' as 'root'  (using password: NO).
220720 18:43:21  version_check Connected to MySQL server
220720 18:43:21  version_check Executing a version check against the server...
220720 18:43:21  version_check Done.
2022-07-20T18:43:21.010844+09:00 0 [Note] [MY-011825] [Xtrabackup] Connecting to MySQL server host: localhost, user: root, password: not set, port: not set, socket: /usr/mysql/8.0.29/data/mysql.sock
2022-07-20T18:43:21.015998+09:00 0 [Note] [MY-011825] [Xtrabackup] Using server version 8.0.29
2022-07-20T18:43:21.020044+09:00 0 [Note] [MY-011825] [Xtrabackup] Executing LOCK INSTANCE FOR BACKUP ...
2022-07-20T18:43:21.023131+09:00 0 [ERROR] [MY-011825] [Xtrabackup] Found tables with row versions due to INSTANT ADD/DROP columns
2022-07-20T18:43:21.023271+09:00 0 [ERROR] [MY-011825] [Xtrabackup] This feature is not stable and will cause backup corruption.
2022-07-20T18:43:21.023352+09:00 0 [ERROR] [MY-011825] [Xtrabackup] Please check https://docs.percona.com/percona-xtrabackup/8.0/em/instant.html for more details.
2022-07-20T18:43:21.023429+09:00 0 [ERROR] [MY-011825] [Xtrabackup] Tables found:
2022-07-20T18:43:21.023513+09:00 0 [ERROR] [MY-011825] [Xtrabackup] d1/t1
2022-07-20T18:43:21.023586+09:00 0 [ERROR] [MY-011825] [Xtrabackup] Please run OPTIMIZE TABLE or ALTER TABLE ALGORITHM=COPY on all listed tables to fix this issue.

あっさりわかりやすく転けた。
エラーメッセージにも書いてあるけど、INSTANT COLUMNはOPTIMIZE TABLEするとINSTANTじゃないカラムになるので、OPTIMIZE。

mysql80 89> OPTIMIZE TABLE d1.t1;
+-------+----------+----------+-------------------------------------------------------------------+
| Table | Op       | Msg_type | Msg_text                                                          |
+-------+----------+----------+-------------------------------------------------------------------+
| d1.t1 | optimize | note     | Table does not support optimize, doing recreate + analyze instead |
| d1.t1 | optimize | status   | OK                                                                |
+-------+----------+----------+-------------------------------------------------------------------+
2 rows in set (0.02 sec)

$ xtrabackup -S /usr/mysql/8.0.29/data/mysql.sock -uroot --backup

..
2022-07-20T18:44:57.129630+09:00 0 [Note] [MY-011825] [Xtrabackup] completed OK!

逆にDROP COLUMNの方。

mysql80 96> SELECT * FROM information_schema.INNODB_TABLES WHERE total_row_versions > 0;
Empty set (0.00 sec)

mysql80 96> ALTER TABLE d1.t1 DROP COLUMN col;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql80 96> SELECT * FROM information_schema.INNODB_TABLES WHERE total_row_versions > 0;
+----------+-------+------+--------+-------+------------+---------------+------------+--------------+--------------------+
| TABLE_ID | NAME  | FLAG | N_COLS | SPACE | ROW_FORMAT | ZIP_PAGE_SIZE | SPACE_TYPE | INSTANT_COLS | TOTAL_ROW_VERSIONS |
+----------+-------+------+--------+-------+------------+---------------+------------+--------------+--------------------+
|    22442 | d1/t1 |   33 |      5 | 21381 | Dynamic    |             0 | Single     |            0 |                  1 |
+----------+-------+------+--------+-------+------------+---------------+------------+--------------+--------------------+
1 row in set (0.01 sec)

$ xtrabackup -S /usr/mysql/8.0.29/data/mysql.sock -uroot --backup
2022-07-20T18:45:53.616425+09:00 0 [Note] [MY-011825] [Xtrabackup] recognized server arguments: --server-id=1 --log_bin=mysql-bin --log-bin-index=bin.index --innodb_buffer_pool_size=60G --innodb_file_per_table=1 --innodb_flush_method=O_DIRECT
2022-07-20T18:45:53.616691+09:00 0 [Note] [MY-011825] [Xtrabackup] recognized client arguments: --user=root --socket=/usr/mysql/8.0.29/data/mysql.sock --user=root --backup=1
xtrabackup version 8.0.29-22 based on MySQL server 8.0.29 Linux (x86_64) (revision id: c31e7ddcce3)
220720 18:45:53  version_check Connecting to MySQL server with DSN 'dbi:mysql:;mysql_read_default_group=xtrabackup;mysql_socket=/usr/mysql/8.0.29/data/mysql.sock' as 'root'  (using password: NO).
220720 18:45:53  version_check Connected to MySQL server
220720 18:45:53  version_check Executing a version check against the server...
220720 18:45:53  version_check Done.
2022-07-20T18:45:53.707364+09:00 0 [Note] [MY-011825] [Xtrabackup] Connecting to MySQL server host: localhost, user: root, password: not set, port: not set, socket: /usr/mysql/8.0.29/data/mysql.sock
2022-07-20T18:45:53.712051+09:00 0 [Note] [MY-011825] [Xtrabackup] Using server version 8.0.29
2022-07-20T18:45:53.714724+09:00 0 [Note] [MY-011825] [Xtrabackup] Executing LOCK INSTANCE FOR BACKUP ...
2022-07-20T18:45:53.717792+09:00 0 [ERROR] [MY-011825] [Xtrabackup] Found tables with row versions due to INSTANT ADD/DROP columns
2022-07-20T18:45:53.717842+09:00 0 [ERROR] [MY-011825] [Xtrabackup] This feature is not stable and will cause backup corruption.
2022-07-20T18:45:53.717856+09:00 0 [ERROR] [MY-011825] [Xtrabackup] Please check https://docs.percona.com/percona-xtrabackup/8.0/em/instant.html for more details.
2022-07-20T18:45:53.717886+09:00 0 [ERROR] [MY-011825] [Xtrabackup] Tables found:
2022-07-20T18:45:53.717909+09:00 0 [ERROR] [MY-011825] [Xtrabackup] d1/t1
2022-07-20T18:45:53.717921+09:00 0 [ERROR] [MY-011825] [Xtrabackup] Please run OPTIMIZE TABLE or ALTER TABLE ALGORITHM=COPY on all listed tables to fix this issue.

同じエラーでアウト。
このエラーを吐いてるところは

https://github.com/percona/percona-xtrabackup/blob/percona-xtrabackup-8.0.29-22/storage/innobase/xtrabackup/src/backup_mysql.cc#L2364-L2401

なので、MySQL 8.0.29以上かつ SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLES WHERE TOTAL_ROW_VERSIONS > 0 でマッチする行があるとエラるようになっている(MySQL 8.0.28とそれ以前にはそもそも total_row_versions カラムがない)

クラッシュリカバリがおかしいのをPercona Serverでは直した、Vanillaではまだ、ってことらしいので、MySQL側でも直ってくれることを祈りつつ。

2022/07/01

mysql_use_result(サーバーサイドバッファリング) vs. history list length


TL;DR

  • トランザクション分離レベルがたとえREAD-UNCOMMITTEDだとしても、クエリの実行中はhistory list lengthは伸びていく

    • REPEATABLE-READ .. トランザクション中はundo recordをパージできない

    • READ-COMMITTED, READ-UNCOMMITTED .. クエリの実行中はundo recordをパージできない

  • ところで、 mysql_use_result はSQLの評価が終わった後に結果セットをクライアントに送信するのを遅延させる(サーバーサイドでバッファリングさせる)ので、クライアントが結果セットを全部読みだしてくれるまでは「MySQL上ではクエリ実行中扱い」

    • というわけで、history list lengthは伸びていった

history list lengthが伸びるかどうかの実験用に、mysqlslapを走らせておく。


$ mysqlslap80 --auto-generate-sql --auto-generate-sql-execute-number=100000000

REPEATABLE-READ.


mysql80 12> SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

Query OK, 0 rows affected (0.00 sec)

mysql80 12> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql80 12> SELECT * FROM d1.t1;
+-----+------+
| num | val  |
+-----+------+
|   1 | one  |
+-----+------+
1 row in set (0.00 sec)

mysql80 12> SELECT count FROM information_schema.innodb_metrics WHERE name = 'trx_rseg_history_len';
+-------+
| count |
+-------+
|  3106 |
+-------+
1 row in set (0.00 sec)

mysql80 12> COMMIT;
Query OK, 0 rows affected (0.00 sec)

mysql80 12> SELECT count FROM information_schema.innodb_metrics WHERE name = 'trx_rseg_history_len';
+-------+
| count |
+-------+
|    60 |
+-------+
1 row in set (0.00 sec)

READ-COMMITTED。
「クエリが終わるまでは伸びる」をSLEEPで表現(history_list_lengthの監視は別のターミナルでやる)

mysql80 12> SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

Query OK, 0 rows affected (0.00 sec)

mysql80 12> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql80 12> SELECT *, SLEEP(30) FROM d1.t1;

mysql80 15> SELECT count FROM information_schema.innodb_metrics WHERE name = 'trx_rseg_history_len';  -- 別ターミナル
+-------+
| count |
+-------+
|  1022 |
+-------+
1 row in set (0.00 sec)

mysql80 12> COMMIT;  -- これを待たずにSELECTが終わった時点でhistory list lengthは減る
Query OK, 0 rows affected (0.00 sec)

READ-UNCOMMITTED

mysql80 12> SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
Query OK, 0 rows affected (0.00 sec)

mysql80 12> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql80 12> SELECT *, SLEEP(30) FROM d1.t1;

mysql80 15> SELECT count FROM information_schema.innodb_metrics WHERE name = 'trx_rseg_history_len';  -- READ-UNCOMMITTEDでさえ実行中は伸びる
+-------+
| count |
+-------+
|   793 |
+-------+
1 row in set (0.00 sec)

ところで、 mysql_use_result を使ったクエリで結果セットが吸い上げられていないものは、 SHOW PROCESSLIST でも Sending to client のStateでクエリが実行中のように出力される(し、実際実行中として扱われているのであろう)

(ちなみにd1.t1のサイズが小さいと、net_bufferに収まってしまって一発で全部送りきられてしまった。ある程度のサイズがないと再現しない)

$ perl -E 'my $conn= DBI->connect("dbi:mysql:d1;mysql_socket=/usr/mysql/8.0.29/data/mysql.sock", "root", ""); my $sth= $conn->prepare("SELECT * FROM d1.t1", { mysql_use_result => 1 }); $sth->execute(); while (my $row= $sth->fetchrow_arrayref()) { sleep 100; }'

| 27 | root            | localhost | d1        | Query   |    5 | Sending to client      | SELECT * FROM d1.t1      |

mysql80 15> SELECT count FROM information_schema.innodb_metrics WHERE name = 'trx_rseg_history_len';
+-------+
| count |
+-------+
|   553 |
+-------+
1 row in set (0.00 sec)

Connector/Jとかでカーソルを使っている場合はこれにあたるかも知れない。というか当たったらしい。
誰かConnector/Jで試してみてほしい。

どうしてもSELECT COUNT(*) せずに正しいレコードの数を数えたい(が、そんなに都合の良いことはなかった)

 

TL;DR

  • innochecksumを使って強引に数えてみた
  • こんなことをするくらいならおとなしくCOUNT(*) した方がマシ

SHOW TABLE STATUS や information_schema.tables は統計情報ベースなので正確な値ではない、でも COUNT(*) はしたくない、という時。

mysql> SHOW TABLE STATUS LIKE 't1'\G
*************************** 1. row ***************************
           Name: t1
         Engine: InnoDB
        Version: 10
     Row_format: Dynamic
           Rows: 94295380
 Avg_row_length: 37
    Data_length: 3515875328
Max_data_length: 0
   Index_length: 3868196864
      Data_free: 6291456
 Auto_increment: NULL
    Create_time: 2022-05-23 21:43:56
    Update_time: 2022-05-23 22:43:29
     Check_time: NULL
      Collation: utf8mb4_bin
       Checksum: NULL
 Create_options:
        Comment:
1 row in set (0.00 sec)

mysql> SELECT COUNT(*) FROM t1;
+-----------+
| COUNT(*)  |
+-----------+
| 100000000 |
+-----------+
1 row in set (8.92 sec)

innochecksum ならそれができるかもなあと思った。

innochecksumは -D オプションでファイル名を指定すると、ibdファイルの中身をページ単位でドバドバ吐き出すことができる。 ( -D /dev/stdout でターミナルに吐ける)

ただしこの時、mysqldが.ibdファイルを掴んでいると↓のようなエラーになるので

$ innochecksum -D /dev/stdout t1.ibd
Error: Unable to lock file:: t1.ibd
fcntl: Resource temporarily unavailable

どうせ「その瞬間のページの状態」しか認識できないんだからと割り切ってどっかにibdファイルをコピーしてそれを掴ませるのをよく(?)やってる。

このコピーの負荷や時間を考えるとCOUNT(*)の方がたぶんマシ。

$ cp -ip t1.ibd ~
$ innochecksum -D /dev/stdout ~/t1.ibd ### コピーしたibdの方にinnochecksumをかける

Filename::/home/yoku0825/t1.ibd
==============================================================================
        PAGE_NO         |               PAGE_TYPE                       |       EXTRA INFO
==============================================================================
#::       0             |               File Space Header               |       -
#::       1             |               Insert Buffer Bitmap            |       -
#::       2             |               Inode page                      |       -
#::       3             |               SDI Index page                  |       index id=18446744073709551615, page level=0, No. of records=2, garbage=0, -
#::       4             |               Index page                      |       index id=145, page level=2, No. of records=189, garbage=0, -
#::       5             |               Index page                      |       index id=146, page level=2, No. of records=91, garbage=0, -
#::       6             |               Index page                      |       index id=147, page level=2, No. of records=91, garbage=0, -
#::       7             |               Index page                      |       index id=148, page level=2, No. of records=91, garbage=0, -
#::       8             |               Index page                      |       index id=145, page level=0, No. of records=220, garbage=7514, -
#::       9             |               Index page                      |       index id=145, page level=0, No. of records=441, garbage=0, -
#::      10             |               Index page                      |       index id=145, page level=0, No. of records=441, garbage=0, -
#::      11             |               Index page                      |       index id=145, page level=0, No. of records=441, garbage=0, -
#::      12             |               Index page                      |       index id=146, page level=0, No. of records=601, garbage=7826, -
#::      13             |               Index page                      |       index id=146, page level=0, No. of records=1203, garbage=0, -
#::      14             |               Index page                      |       index id=147, page level=0, No. of records=601, garbage=7826, -
#::      15             |               Index page                      |       index id=147, page level=0, No. of records=1203, garbage=0, -
#::      16             |               Index page                      |       index id=148, page level=0, No. of records=1202, garbage=0, -
#::      17             |               Index page                      |       index id=148, page level=0, No. of records=601, garbage=7826, -
#::      18             |               Index page                      |       index id=145, page level=0, No. of records=441, garbage=0, -
#::      19             |               Index page                      |       index id=146, page level=0, No. of records=1203, garbage=0, -
#::      20             |               Index page                      |       index id=147, page level=0, No. of records=1203, garbage=0, -
#::      21             |               Index page                      |       index id=148, page level=0, No. of records=1203, garbage=0, -

..

index id は information_schema.innodb_indexes から引ける ( innodb_tables とJOINするとテーブルで絞りやすい )

mysql> SELECT * FROM information_schema.innodb_indexes JOIN information_schema.innodb_tables USING(table_id) WHERE innodb_tables.name = 'd1/t1';
+----------+----------+---------+------+----------+---------+-------+-----------------+-------+------+--------+-------+------------+---------------+------------+--------------+
| TABLE_ID | INDEX_ID | NAME    | TYPE | N_FIELDS | PAGE_NO | SPACE | MERGE_THRESHOLD | NAME  | FLAG | N_COLS | SPACE | ROW_FORMAT | ZIP_PAGE_SIZE | SPACE_TYPE | INSTANT_COLS |
+----------+----------+---------+------+----------+---------+-------+-----------------+-------+------+--------+-------+------------+---------------+------------+--------------+
|     1061 |      145 | PRIMARY |    3 |        6 |       4 |     4 |              50 | d1/t1 |   33 |      7 |     4 | Dynamic    |             0 | Single     |            0 |
|     1061 |      146 | c2      |    0 |        2 |       5 |     4 |              50 | d1/t1 |   33 |      7 |     4 | Dynamic    |             0 | Single     |            0 |
|     1061 |      147 | c3      |    0 |        2 |       6 |     4 |              50 | d1/t1 |   33 |      7 |     4 | Dynamic    |             0 | Single     |            0 |
|     1061 |      148 | c4      |    0 |        2 |       7 |     4 |              50 | d1/t1 |   33 |      7 |     4 | Dynamic    |             0 | Single     |            0 |
+----------+----------+---------+------+----------+---------+-------+-----------------+-------+------+--------+-------+------------+---------------+------------+--------------+
4 rows in set (0.00 sec)

なんか gargage=? の値を引いたりとかいろいろしてみたけど引かない方が合ってるっぽい。 page level=0 (これがリーフノードらしい) の数だけを数えるのが正解っぽい?

$ innochecksum -D /dev/stdout ~/t1.ibd | grep 'Index page' | grep -v 'SDI' | grep 'page level=0' | perl -MData::Dumper -nlE 'BEGIN { $counter }; /index id=(\d+).*records=(\d+)/; $counter->{$1} += $2; END { print Dumper $counter }'
$VAR1 = {
          '147' => '100000000',
          '145' => '100000000',
          '148' => '100000601',
          '146' => '100000000'
        };

なんで INDEX c4(c4) だけズレるのかがわからない…。