論理削除とオプティマイザ (のつもりだったけどただのメモ)

タイトルまで書いたけど面倒になったんでやめた。

% seq 1000000 > aho.out
mysql> create table aho (id int, col1 int default null, col2 int default null, primary key (id), key (col1));
mysql> load data local infile '/home/ichii386/aho.out' into table aho (id);

col1 が論理削除フラグだと思ってください。

mysql> select sql_no_cache * from aho where id in (1,2,3,4,5,6,7,8,9,10) and col1 is null;
+----+------+------+
| id | col1 | col2 |
+----+------+------+
|  1 | NULL | NULL |
|  2 | NULL | NULL |
|  3 | NULL | NULL |
|  4 | NULL | NULL |
|  5 | NULL | NULL |
|  6 | NULL | NULL |
|  7 | NULL | NULL |
|  8 | NULL | NULL |
|  9 | NULL | NULL |
| 10 | NULL | NULL |
+----+------+------+
10 rows in set (0.13 sec)

妙に遅い。

mysql> select sql_no_cache * from aho force index (primary) where id in (1,2,3,4,5,6,7,8,9,10) and col1 is null;
+----+------+------+
| id | col1 | col2 |
+----+------+------+
|  1 | NULL | NULL |
|  2 | NULL | NULL |
|  3 | NULL | NULL |
|  4 | NULL | NULL |
|  5 | NULL | NULL |
|  6 | NULL | NULL |
|  7 | NULL | NULL |
|  8 | NULL | NULL |
|  9 | NULL | NULL |
| 10 | NULL | NULL |
+----+------+------+
10 rows in set (0.00 sec)

期待通り。

                "best_access_path": {
                  "considered_access_paths": [
                    {
                      "access_type": "ref",
                      "index": "col1",
                      "rows": 10,
                      "cost": 12,
                      "chosen": true
                    },
                    {
                      "access_type": "range",
                      "rows": 8,
                      "cost": 14.02,
                      "chosen": false
                    }
                  ]
                },

理由は select に col2 が入ってるのに col1 is null な ref を使っちゃうから。

なんで practical にも論理削除はやめてほしい。 orm の都合で index hinting 使えないとかあるあるなんで。