Kouhei Sutou
kou****@clear*****
2015年 12月 26日 (土) 23:12:12 JST
須藤です。 報告ありがとうございます! まだ大丈夫ではないので教えてください! > -- run.sql の処理が完了頃に Indexの使用/未使用で SELECT 結果に差がでる > SELECT a_id > FROM tbl_mroonga AS tav_ignore > IGNORE INDEX (t2_date) > WHERE t2_date <= current_timestamp > ; > SELECT a_id > FROM tbl_mroonga AS tav_origin > WHERE tav_origin.t2_date <= current_timestamp > ; このときの具体的な結果を教えてもらえますか?たぶん、件数が違 うとか、片方にはあってもう片方にはないレコードがあるというこ とだと思うんですが。。。 手元でも試してみたのですが、たしかに、このSELECTだと違いがあ ります。しかし、次のようにORDER BY a_idとすると違いがありま せん。 -- SELECT a_id FROM tbl_mroonga AS tav_ignore IGNORE INDEX (t2_date) WHERE t2_date <= current_timestamp ORDER BY a_id; SELECT a_id FROM tbl_mroonga AS tav_origin WHERE tav_origin.t2_date <= current_timestamp ORDER BY a_id; -- なお、ORDER BYがないときの順序は不定なので、順序が違うだけの 違いは仕様です。 In <20151****@domai*****> "[groonga-dev,03802] Mroonga で timestamp 型の index が破損するパターンがある(ストレージモード)" on Thu, 24 Dec 2015 19:37:27 +0900, 各務 洋 <kagam****@outwa*****> wrote: > お世話になります、本日サンタではなくベイマックスと言われた各務です。 > > なんとか TIMESTAMP 型のインデックスが破損するパターンを掴めたようですので > ご報告させていただきます。 > > 条件: > Mroonga のレコードを削除する事。 > InnoDB と Mroonga のレコード操作が同一のトランザクション内で行われている事。 > 同様のトランザクション処理がいくつか同時に実行されている事。 > そのいずれかの処理中になんらかの理由でエラーになる事。(Roll Back の発生) > > を満たした際に発生するようです。 > (ありゃ、トランザクション内に削除処理がありました) > > ただ、下記の再現手順を作っていて分かったのですが、トランザクションは関 > 係ない比較的単純な DELETE でも処理件数が多いと発生するのかもしれません。 > > というのも 再現手順での run.sql を作成する際、Mroonga のテーブルから一 > 旦消しながら削除用SQLを作成しているのですが、指定件数分 DELETE 文が生 > 成されない事があります。 Null が返る時があるのです。 > (最後に Null を足しているのはその名残) > > innodb 側のテーブルで同じ処理を行うと期待通りの件数が出力され、また > 対象レコードも 0 件になります。 > > > 環境: > CentOS 7.1 > MySQL 5.7.9 > Mroonga 5.10 > (CentOS 6.4, MySQL 5.6.26 でも同様です) > > > 再現手順: > > CREATE DATABASE db_test; > USE db_test; > DROP TABLE IF EXISTS `tbl_mroonga`; > CREATE TABLE `tbl_mroonga` ( > `id` BIGINT(20) NOT NULL AUTO_INCREMENT, > `t1_date` TIMESTAMP NOT NULL DEFAULT current_timestamp, > `t2_date` TIMESTAMP NOT NULL DEFAULT '0000-00-00', > `a_id` BIGINT(20) NOT NULL Default 0, > `t_text` LONGTEXT, > PRIMARY KEY (`id`), > UNIQUE KEY `a_id` (`a_id`), > INDEX `t2_date` (`t2_date`), > FULLTEXT INDEX `t_text` (`t_text` ) COMMENT 'normalizer "NormalizerMySQLUnicodeCIExceptKanaCIKanaWithVoicedSoundMark"' > ) ENGINE=mroonga DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; > > DROP TABLE IF EXISTS `tbl_innodb`; > CREATE TABLE `tbl_innodb` ( > `id` BIGINT(20) NOT NULL AUTO_INCREMENT, > `t1_date` TIMESTAMP NOT NULL DEFAULT current_timestamp, > `t2_date` TIMESTAMP NOT NULL DEFAULT '0000-00-00', > `oa_id` BIGINT(20) NOT NULL Default 0, > PRIMARY KEY (`id`), > INDEX `oa_id` (`oa_id`), > INDEX `t2_date` (`t2_date`) > > ) ENGINE=Innodb DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; > > DROP TABLE IF EXISTS `tbl_dummy`; > CREATE TABLE `tbl_dummy` ( > `id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT, > `t2_date` TIMESTAMP NOT NULL DEFAULT current_timestamp > ) ENGINE=Innodb DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; > > -- レコードを増やす > INSERT INTO tbl_dummy (t2_date) VALUES ((SELECT ADDTIME(CONCAT_WS(' ','2015-06-01' + INTERVAL RAND() * 365 DAY, '00:00:00'), SEC_TO_TIME(FLOOR(0 + (RAND() * 86401)))))); > INSERT INTO tbl_dummy (t2_date) SELECT ADDTIME(CONCAT_WS(' ','2015-06-01' + INTERVAL RAND() * 365 DAY, '00:00:00'), SEC_TO_TIME(FLOOR(0 + (RAND() * 86401)))) FROM tbl_dummy; > INSERT INTO tbl_dummy (t2_date) SELECT ADDTIME(CONCAT_WS(' ','2015-06-01' + INTERVAL RAND() * 365 DAY, '00:00:00'), SEC_TO_TIME(FLOOR(0 + (RAND() * 86401)))) FROM tbl_dummy; > INSERT INTO tbl_dummy (t2_date) SELECT ADDTIME(CONCAT_WS(' ','2015-06-01' + INTERVAL RAND() * 365 DAY, '00:00:00'), SEC_TO_TIME(FLOOR(0 + (RAND() * 86401)))) FROM tbl_dummy; > INSERT INTO tbl_dummy (t2_date) SELECT ADDTIME(CONCAT_WS(' ','2015-06-01' + INTERVAL RAND() * 365 DAY, '00:00:00'), SEC_TO_TIME(FLOOR(0 + (RAND() * 86401)))) FROM tbl_dummy; > INSERT INTO tbl_dummy (t2_date) SELECT ADDTIME(CONCAT_WS(' ','2015-06-01' + INTERVAL RAND() * 365 DAY, '00:00:00'), SEC_TO_TIME(FLOOR(0 + (RAND() * 86401)))) FROM tbl_dummy; > INSERT INTO tbl_dummy (t2_date) SELECT ADDTIME(CONCAT_WS(' ','2015-06-01' + INTERVAL RAND() * 365 DAY, '00:00:00'), SEC_TO_TIME(FLOOR(0 + (RAND() * 86401)))) FROM tbl_dummy; > INSERT INTO tbl_dummy (t2_date) SELECT ADDTIME(CONCAT_WS(' ','2015-06-01' + INTERVAL RAND() * 365 DAY, '00:00:00'), SEC_TO_TIME(FLOOR(0 + (RAND() * 86401)))) FROM tbl_dummy; > INSERT INTO tbl_dummy (t2_date) SELECT ADDTIME(CONCAT_WS(' ','2015-06-01' + INTERVAL RAND() * 365 DAY, '00:00:00'), SEC_TO_TIME(FLOOR(0 + (RAND() * 86401)))) FROM tbl_dummy; > INSERT INTO tbl_dummy (t2_date) SELECT ADDTIME(CONCAT_WS(' ','2015-06-01' + INTERVAL RAND() * 365 DAY, '00:00:00'), SEC_TO_TIME(FLOOR(0 + (RAND() * 86401)))) FROM tbl_dummy; > INSERT INTO tbl_dummy (t2_date) SELECT ADDTIME(CONCAT_WS(' ','2015-06-01' + INTERVAL RAND() * 365 DAY, '00:00:00'), SEC_TO_TIME(FLOOR(0 + (RAND() * 86401)))) FROM tbl_dummy; > INSERT INTO tbl_dummy (t2_date) SELECT ADDTIME(CONCAT_WS(' ','2015-06-01' + INTERVAL RAND() * 365 DAY, '00:00:00'), SEC_TO_TIME(FLOOR(0 + (RAND() * 86401)))) FROM tbl_dummy; > INSERT INTO tbl_dummy (t2_date) SELECT ADDTIME(CONCAT_WS(' ','2015-06-01' + INTERVAL RAND() * 365 DAY, '00:00:00'), SEC_TO_TIME(FLOOR(0 + (RAND() * 86401)))) FROM tbl_dummy; > INSERT INTO tbl_dummy (t2_date) SELECT ADDTIME(CONCAT_WS(' ','2015-06-01' + INTERVAL RAND() * 365 DAY, '00:00:00'), SEC_TO_TIME(FLOOR(0 + (RAND() * 86401)))) FROM tbl_dummy; > INSERT INTO tbl_dummy (t2_date) SELECT ADDTIME(CONCAT_WS(' ','2015-06-01' + INTERVAL RAND() * 365 DAY, '00:00:00'), SEC_TO_TIME(FLOOR(0 + (RAND() * 86401)))) FROM tbl_dummy; > > TRUNCATE TABLE tbl_mroonga; > INSERT INTO tbl_mroonga (a_id, t2_date) > SELECT id, t2_date FROM tbl_dummy ORDER BY id; > > TRUNCATE TABLE tbl_innodb; > INSERT INTO tbl_innodb (oa_id, t2_date) > SELECT id, t2_date FROM tbl_dummy ORDER BY id; > > ## 概ね総レコード数の半分程度を削除対象にする。本番環境を模して連番で消さないようにする。 > cat << '__EOF__' >while.sql > SET @a_id:=(SELECT a_id FROM tbl_mroonga WHERE t2_date <= current_timestamp ORDER BY RAND() LIMIT 1); > SELECT CONCAT('START TRANSACTION; UPDATE tbl_innodb SET oa_id = 0 WHERE oa_id =', @ a_id,'; DELETE FROM tbl_mroonga WHERE a_id = ', @ a_id,'; COMMIT WORK;') AS ''; > DELETE FROM tbl_mroonga WHERE a_id = @a_id; > __EOF__ > > SELECT COUNT(id) FROM tbl_dummy WHERE t2_date <= current_timestamp; > > ## ↑の count の数(対象レコード分)だけ回す > rm -f run.sql;i=0; while [ ${i} -lt 4625 ]; do ((i ++)); mysql -N db_test < while.sql >> run.sql; echo ${i}; done > echo "Null">> run.sql > echo "Null">> run.sql > ## ↑SQLエラーにする > > -- いったんレコードを戻す > TRUNCATE TABLE tbl_mroonga; > INSERT INTO tbl_mroonga (a_id, t2_date) > SELECT id, t2_date FROM tbl_dummy ORDER BY id; > > ## どん! > mysql db_test < run.sql > > を実行しながら、別セッションで rollback するSQLをガンガン実行 > START TRANSACTION; UPDATE tbl_innodb SET oa_id = 0 WHERE oa_id =2756; DELETE FROM tbl_mroonga WHERE a_id = 2756; ROLLBACK WORK; > START TRANSACTION; UPDATE tbl_innodb SET oa_id = 0 WHERE oa_id =0; DELETE FROM tbl_mroonga WHERE a_id = 2756; ROLLBACK WORK; > > -- run.sql の処理が完了頃に Indexの使用/未使用で SELECT 結果に差がでる > SELECT a_id > FROM tbl_mroonga AS tav_ignore > IGNORE INDEX (t2_date) > WHERE t2_date <= current_timestamp > ; > SELECT a_id > FROM tbl_mroonga AS tav_origin > WHERE tav_origin.t2_date <= current_timestamp > ; > > 完全ではないのですが、再現性はそこそこあります。 > > GTID を使用する順同期レプリケーション時に怒られてしまうので、トランザ > クション処理内からは Mroonga を外す処理に切替中です。 > > よろしくお願いします。 > > > ---- > 各務 > kagam****@outwa***** > > _______________________________________________ > groonga-dev mailing list > groon****@lists***** > http://lists.osdn.me/mailman/listinfo/groonga-dev