[groonga-dev,01097] mroongaにおける、テーブル内情報と統計情報の不正について

アーカイブの一覧に戻る

磯部 和広 k-iso****@rozet*****
2012年 11月 13日 (火) 21:45:20 JST


いつもお世話になっております。

首題の件につき質問させて下さい。

動作環境は、下記です。

[root @ DB09 data]# head -n 1 groonga.log
2012-05-18 18:50:01.795320|n|e897e700|mroonga 2.02 started.
[root @ DB09 data]# cat /etc/redhat-release
CentOS release 6.2 (Final)
[root @ DB09 data]#

現在、プライマリーキーを張った「id」フィールドに、
SQLでselectを行うと
 何故か「0」と表示される行が3つある
という状況になってしまっています。

mysql> desc RZ_COMPARISON;
+----------------------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| category_id | int(11) | NO | | NULL | |
| original_data_id | int(11) | YES | | NULL | |
| whole_flag | tinyint(4) | YES | | NULL | |
| lang_type | tinyint(4) | YES | | NULL | |
| wa_original | mediumtext | NO | MUL | NULL | |
| std_original | mediumtext | NO | MUL | NULL | |
| wa_trans | mediumtext | NO | MUL | NULL | |
| original | mediumtext | NO | MUL | NULL | |
| trans | mediumtext | NO | MUL | NULL | |
| original_line_length | int(11) | YES | | NULL | |
| trans_line_length | int(11) | YES | | NULL | |
| reg_date | datetime | YES | | NULL | |
| reg_id | int(11) | YES | | NULL | |
| upd_date | datetime | YES | | NULL | |
| upd_id | int(11) | YES | | NULL | |
+----------------------+------------+------+-----+---------+----------------+
16 rows in set (0.00 sec)

mysql> select id from RZ_COMPARISON where original_line_length = 0;
+----+
| id |
+----+
| 0 |
| 0 |
| 0 |
+----+
3 rows in set (0.00 sec)

mysql>

プライマリーキーなので、本来有り得ない状況なのですが・・・

が、where id=0 を指定してselectしても1件もヒットしません。

mysql> select id from RZ_COMPARISON where id = 0;
Empty set (0.00 sec)

mysql>


どうも、nroongaエンジン固有の問題のようです・・・



これだけだと、問題解決の為に何も手掛かりが得られないので
下記の実験を行いました。

mysql> select count(1) from RZ_COMPARISON;
+----------+
| count(1) |
+----------+
| 2656 |
+----------+
1 row in set (0.00 sec)

mysql> select min(id), max(id) from RZ_COMPARISON;
+---------+---------+
| min(id) | max(id) |
+---------+---------+
| 246619 | 250513 |
+---------+---------+
1 row in set (0.00 sec)

mysql> select count(1) from RZ_COMPARISON where id <= 250513;
+----------+
| count(1) |
+----------+
| 2656 |
+----------+
1 row in set (0.01 sec)

mysql> select count(1) from RZ_COMPARISON where id >= 246619;
+----------+
| count(1) |
+----------+
| 1587 |
+----------+
1 row in set (0.00 sec)

mysql>

御覧のように、全件の数値と、
 id <= max(id) のものは件数が一致しますが
 id >= min(id) のものは件数が一致しない
という状況です。

繰り返しますが、idはプライマリーキーです。
当然インデックスが張ってあります。

どうも、インデックスの統計情報がおかしくなっているようです。
※インデックスを指定してのカウントは、統計情報を使用すると推測しています。
 インデックスを張ってある項目のminやmax値も、同様に
 インデックスの統計情報から取得しているのだと思います。

次に、データをファイルに出力してみて状況を見てみました。

[root @ DB09 data]# echo 'select id from RZ_COMPARISON' | mysql rz_00003 >
/tmp/a
[root @ DB09 data]# wc -l /tmp/a
2657 /tmp/a
[root @ DB09 data]# head -n 2 /tmp/a
id
246619
[root @ DB09 data]# tail -n 2 /tmp/a
250509
250510
[root @ DB09 data]#

あれれ?
変です。

idの最小値と、ファイルに出力されたidの最小値は一致するのですが
最大値が一致しません。

念の為ソートしてみましたが、結果は一緒です。

[root @ DB09 data]# echo 'select id from RZ_COMPARISON order by id' |
mysql rz_00003 > /tmp/b
[root @ DB09 data]# wc -l /tmp/b
2657 /tmp/b
[root @ DB09 data]# head -n 2 /tmp/b
id
246619
[root @ DB09 data]# tail -n 2 /tmp/b
250509
250510
[root @ DB09 data]#

更に確認しました。

[root @ DB09 data]# sort -n /tmp/b | head
id
883
884
885
886
887
888
889
890
891
[root @ DB09 data]#

SQLで取得したIDの最小値より小さいIDが・・・

/tmp/b は、order by idを指定してあったのに、正しくソートされていません。

[root @ DB09 data]# grep -n '^883' /tmp/b
4:883
[root @ DB09 data]#

4行目に出現しているようなので、先頭10件を表示してみます。

[root @ DB09 data]# head -n 10 /tmp/b
id
246619
246621
883
884
885
886
887
888
889
[root @ DB09 data]# head -n 10 /tmp/a
id
246619
246621
883
884
885
886
887
888
889
[root @ DB09 data]#

order by句もインデックスを使用する筈なので、
やはりインデックス絡みのようです。


というわけで、首題の件名となりました。

どうも、
 select id from RZ_COMPARISON where original_line_length = 0;
 にて、ありえない筈のプリマリーキーに同一の「0」として見える値が
 3件見える
のと
 IDの最大値と、データ出力した際のIDの最大値の差が3
とが関係しているようです。

それとは別に、min関係のインデックス情報がおかしいようです。
 

ちなみに、経緯は下記です。

このテーブルのプライマリーキーのid欄には、AUTO_INCREMENT属性が付いていますが
それとは別建てで
 ・IDだけを連番管理するテーブルに新規IDを採番
 ・採番したIDを用いて、このテーブルにデータをインサート
する仕組みになっています。

その際に
 採番用テーブルのID値の最大値と、実際のデータのIDの最大値が違う(3件ず
れている)
のに、別のエンジニアがたまたま気付きました。

で、自分が相談されて調査した所・・・という流れです。

尚、データは随時、追加や削除を繰り返していますのでidは飛び飛びになります。

最後に、テーブルの定義を載せておきます。

CREATE TABLE `RZ_COMPARISON` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`category_id` int(11) NOT NULL,
`original_data_id` int(11) DEFAULT NULL,
`whole_flag` tinyint(4) DEFAULT NULL,
`lang_type` tinyint(4) DEFAULT NULL,
`wa_original` mediumtext NOT NULL,
`std_original` mediumtext NOT NULL,
`wa_trans` mediumtext NOT NULL,
`original` mediumtext NOT NULL,
`trans` mediumtext NOT NULL,
`original_line_length` int(11) DEFAULT NULL,
`trans_line_length` int(11) DEFAULT NULL,
`reg_date` datetime DEFAULT NULL,
`reg_id` int(11) DEFAULT NULL,
`upd_date` datetime DEFAULT NULL,
`upd_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
FULLTEXT KEY `index_so` (`std_original`) COMMENT 'parser "TokenDelimit"',
FULLTEXT KEY `index_swt` (`wa_trans`) COMMENT 'parser\n"TokenDelimit"',
FULLTEXT KEY `index_o` (`original`),
FULLTEXT KEY `index_t` (`trans`),
FULLTEXT KEY `index_wo` (`wa_original`) COMMENT 'parser\n"TokenDelimit"'
) ENGINE=mroonga DEFAULT CHARSET=utf8;




groonga-dev メーリングリストの案内
アーカイブの一覧に戻る