Bug #2651

複合IndexをWHERE句内でBETWEEN、又は<を使用して絞り込むとORDER DESCの場合のみ結果が0行になる

Added by Naoya Murakami over 2 years ago. Updated over 2 years ago.

Status:完了Start date:09/11/2014
Priority:NormalDue date:
Assignee:Kouhei Sutou% Done:

100%

Category:-
Target version:-

Description

Twitterで@foamcentimeさんより、以下の報告をいただきました。

・現象 複合IndexをFORCE INDEXで指定し、ORDER句に指定したカラムをWHERE句内でBETWEEN、又は<を使用して絞り込むとORDER DESCの場合のみ結果が0行になる

・環境 OS:Debian7.6 MySQL:5.6.20 Groonga:4.5.0-1 Mroonga:4.50

Mroongaはソースからビルドしgrn_expr_flagsにGRN_EXPR_ALLOW_COLUMNを追加しています

・検証用SQL

CREATE TABLE `table_test` (
    `id` INT,
    `date` DATETIME,
    `flag` TINYINT,
    PRIMARY KEY (`id`),
    INDEX `index_date` (`date`),
    INDEX `index_flag` (`flag`),
    INDEX `index_flag_date` (`flag`,`date`)
) ENGINE = 'Mroonga';

INSERT INTO `table_test` (`id`,`date`,`flag`) VALUES (1,'2014-01-01 00:00:00',1);
INSERT INTO `table_test` (`id`,`date`,`flag`) VALUES (2,'2014-01-02 00:00:00',1);

SELECT * FROM `table_test` FORCE INDEX (`index_flag_date`) 
WHERE `flag` = 1 AND `date` BETWEEN '2000-01-01 00:00:00' AND '2015-01-01 00:00:00' 
ORDER BY `date` DESC LIMIT 0,100;

SELECT * FROM `table_test` FORCE INDEX (`index_flag_date`)
WHERE `flag` = 1 AND `date` < '2015-01-01 00:00:00'  
ORDER BY `date` DESC LIMIT 0,100;

・補足 FORCE INDEXが無い場合、index_flag_dateが使用される様ですがDESCも問題ないようです

http://blog.livedoor.jp/foamcentime/mroonga-test.txt

History

#1 Updated by Naoya Murakami over 2 years ago

もう少し条件を簡素化し、以下のSQLでも再現しました。

CREATE TABLE `table_test` (
    `id` INT,
    `date` DATETIME,
    `flag` TINYINT,
    PRIMARY KEY (`id`),
    INDEX `index_flag_date` (`flag`,`date`)
) ENGINE = 'Mroonga';

INSERT INTO `table_test` (`id`,`date`,`flag`) VALUES (1,'2014-01-01 00:00:00',1);
INSERT INTO `table_test` (`id`,`date`,`flag`) VALUES (2,'2014-01-02 00:00:00',1);

SELECT * FROM `table_test` 
WHERE `flag` = 1 AND`date` < '2015-01-01 00:00:00'  
ORDER BY `date` DESC LIMIT 0,100;

このSQLでは、以下のindex_read_mapを通るようなのですが、正しくレコードが取れていないかもしれません。 私がさくっと追えたのは、とりあえず、ここまでです。

https://github.com/mroonga/mroonga/blob/master/ha_mroonga.cpp#L6887-L6893

#2 Updated by Naoya Murakami over 2 years ago

これは、flagsとdateの複合インデックスをflagsで前方一致検索させるケースだと思います。

https://github.com/mroonga/mroonga/blob/master/ha_mroonga.cpp#L6775-L6777

以下のカーソルは、size_minが11なのですが(INT(11)だから?)、size_minを1に置き換えると成功します。

数値の場合の複合キーのサイズ取得処理等が怪しい気がします。

もう少し調べてみます。

#3 Updated by Kouhei Sutou over 2 years ago

  • Status changed from 新規 to 完了
  • Assignee set to Kouhei Sutou
  • % Done changed from 0 to 100

報告ありがとうございます! 困っている人のフォロー、とても助かります!

私も調べてみました!サイズの取得はあっていて、今までMroongaが想定していない呼ばれ方がある、けど、それに対応していなかったのが原因でした。

ということで対応しました!

https://github.com/mroonga/mroonga/commit/1f06d56d74dfba841eb0e6590b6c7b4a441df3b4

ORDER BYではインデックスを使えないけど、WHEREだけでインデックスを使う場合に今回の呼ばれ方をするみたいです。ただ、そのケースは性能が落ちるので、普通はWHEREでもORDER BYでもインデックスを使えるようにインデックスを張るのがいいんですよねぇ。今回の再現ケースだとflag, dateじゃなく、date, flagにするとWHEREでもORDER BYでもインデックスが効くようになります。

#4 Updated by Naoya Murakami over 2 years ago

おお。。速い!ありがとうございます! 理解しました!

https://github.com/mroonga/mroonga/commit/1f06d56d74dfba841eb0e6590b6c7b4a441df3b4

#5 Updated by Kouhei Sutou over 2 years ago

あ、インデックスに指定するカラムの順番を変えてもインデックスは効かないですねぇ。範囲検索が一番最後じゃなくなっちゃう。。。

Also available in: Atom PDF