Description:
Certain Full-Text queries are failing when an additional secondary index is used.
How to repeat:
I'll attach SQL below to this bugs.
1. Create test table/data
mysql> CREATE TABLE `ft_max_test` (
-> `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
-> `doc_id` int(10) unsigned NOT NULL DEFAULT '0',
-> `title` varchar(255) NOT NULL DEFAULT 'Untitled',
-> `body` mediumtext,
-> PRIMARY KEY (`id`),
-> KEY `doc_id` (`doc_id`),
-> FULLTEXT KEY `title` (`title`),
-> FULLTEXT KEY `body` (`body`)
-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
Query OK, 0 rows affected (0.04 sec)
mysql> INSERT INTO ft_max_test VALUES
-> (1, 1, 'Insert into table', 'insert into table select from'),
-> (2, 1, 'Delete from table', 'some body text here'),
-> (3, 1, 'Update', 'perform update'),
-> (4, 2, 'Insert into table', 'insert into table select from'),
-> (5, 2, 'Delete from table', 'some body text here'),
-> (6, 2, 'Update', 'perform update'),
-> (7, 3, 'Insert into table', 'insert into table select from'),
-> (8, 3, 'Delete from table', 'some body text here'),
-> (9, 3, 'Update', 'perform update'),
-> (10, 4, 'Insert into table', 'insert into table select from'),
-> (11, 4, 'Delete from table', 'some body text here'),
-> (12, 4, 'Update', 'perform update');
Query OK, 12 rows affected (0.00 sec)
Records: 12 Duplicates: 0 Warnings: 0
2. Perform FT search getting max relevance for title and body (without using doc_id index)
mysql> SELECT
-> MAX(MATCH (title) AGAINST ('table' IN BOOLEAN MODE)) AS rel1,
-> MAX(MATCH (body) AGAINST ('table' IN BOOLEAN MODE)) AS rel2
-> FROM
-> ft_max_test
-> WHERE
-> MATCH (title) AGAINST ('table' IN BOOLEAN MODE) OR
-> MATCH (body) AGAINST ('table' IN BOOLEAN MODE);
+----------------------+---------------------+
| rel1 | rel2 |
+----------------------+---------------------+
| 0.031008131802082062 | 0.22764469683170319 |
+----------------------+---------------------+
1 row in set (0.01 sec)
3. Examine title and body relevance values for rows matched
mysql> SELECT
-> id,
-> doc_id,
-> MATCH (title) AGAINST ('table' IN BOOLEAN MODE) AS rel1,
-> MATCH (body) AGAINST ('table' IN BOOLEAN MODE) AS rel2
-> FROM
-> ft_max_test
-> WHERE
-> MATCH (title) AGAINST ('table' IN BOOLEAN MODE) OR
-> MATCH (body) AGAINST ('table' IN BOOLEAN MODE);
+----+--------+----------------------+---------------------+
| id | doc_id | rel1 | rel2 |
+----+--------+----------------------+---------------------+
| 1 | 1 | 0.031008131802082062 | 0.22764469683170319 |
| 2 | 1 | 0.031008131802082062 | 0 |
| 4 | 2 | 0.031008131802082062 | 0.22764469683170319 |
| 5 | 2 | 0.031008131802082062 | 0 |
| 7 | 3 | 0.031008131802082062 | 0.22764469683170319 |
| 8 | 3 | 0.031008131802082062 | 0 |
| 10 | 4 | 0.031008131802082062 | 0.22764469683170319 |
| 11 | 4 | 0.031008131802082062 | 0 |
+----+--------+----------------------+---------------------+
8 rows in set (0.00 sec)
4. Perform FT search getting max relevance for title and body using doc_id index (Doesn't Work)
mysql> SELECT
-> MAX(MATCH (title) AGAINST ('table' IN BOOLEAN MODE)) AS rel1,
-> MAX(MATCH (body) AGAINST ('table' IN BOOLEAN MODE)) AS rel2
-> FROM
-> ft_max_test
-> WHERE
-> doc_id = 1 AND
-> (MATCH (title) AGAINST ('table' IN BOOLEAN MODE) OR
-> MATCH (body) AGAINST ('table' IN BOOLEAN MODE));
+------+------+
| rel1 | rel2 |
+------+------+
| NULL | NULL |
+------+------+
1 row in set (0.00 sec)
5. Run EXPLAIN to confirm doc_id index was used
mysql> EXPLAIN SELECT
-> MAX(MATCH (title) AGAINST ('table' IN BOOLEAN MODE)) AS rel1,
-> MAX(MATCH (body) AGAINST ('table' IN BOOLEAN MODE)) AS rel2
-> FROM
-> ft_max_test
-> WHERE
-> doc_id = 1 AND
-> (MATCH (title) AGAINST ('table' IN BOOLEAN MODE) OR
-> MATCH (body) AGAINST ('table' IN BOOLEAN MODE));
+----+-------------+-------------+------------+------+---------------+--------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------------+------------+------+---------------+--------+---------+-------+------+----------+-------------+
| 1 | SIMPLE | ft_max_test | NULL | ref | doc_id | doc_id | 4 | const | 3 | 20.99 | Using where |
+----+-------------+-------------+------------+------+---------------+--------+---------+-------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
6. Try to get title and body relevance values for rows matched
mysql> SELECT
-> id,
-> doc_id,
-> MATCH (title) AGAINST ('table' IN BOOLEAN MODE) AS rel1,
-> MATCH (body) AGAINST ('table' IN BOOLEAN MODE) AS rel2
-> FROM
-> ft_max_test
-> WHERE
-> doc_id = 1 AND
-> (MATCH (title) AGAINST ('table' IN BOOLEAN MODE) OR
-> MATCH (body) AGAINST ('table' IN BOOLEAN MODE));
Empty set (0.00 sec)
7. Try 4 and 6 above again ignoring the doc_id index ... Works!
mysql> SELECT
-> MAX(MATCH (title) AGAINST ('table' IN BOOLEAN MODE)) AS rel1,
-> MAX(MATCH (body) AGAINST ('table' IN BOOLEAN MODE)) AS rel2
-> FROM
-> ft_max_test
-> IGNORE
-> index(doc_id)
-> WHERE
-> doc_id = 1 AND
-> (MATCH (title) AGAINST ('table' IN BOOLEAN MODE) OR
-> MATCH (body) AGAINST ('table' IN BOOLEAN MODE));
+----------------------+---------------------+
| rel1 | rel2 |
+----------------------+---------------------+
| 0.031008131802082062 | 0.22764469683170319 |
+----------------------+---------------------+
1 row in set (0.01 sec)
mysql> SELECT
-> id,
-> doc_id,
-> MATCH (title) AGAINST ('table' IN BOOLEAN MODE) AS rel1,
-> MATCH (body) AGAINST ('table' IN BOOLEAN MODE) AS rel2
-> FROM
-> ft_max_test
-> IGNORE
-> index(doc_id)
-> WHERE
-> doc_id = 1 AND
-> (MATCH (title) AGAINST ('table' IN BOOLEAN MODE) OR
-> MATCH (body) AGAINST ('table' IN BOOLEAN MODE));
+----+--------+----------------------+---------------------+
| id | doc_id | rel1 | rel2 |
+----+--------+----------------------+---------------------+
| 1 | 1 | 0.031008131802082062 | 0.22764469683170319 |
| 2 | 1 | 0.031008131802082062 | 0 |
+----+--------+----------------------+---------------------+
2 rows in set (0.00 sec)
Suggested fix:
May be related to bug #80244.