Вы можете разбить запрос на две части и объединить их вместе:
SELECT idx1, NULL AS idx2
FROM myTable
WHERE idx1 IN (1,2,3)
UNION ALL
SELECT NULL, idx2
FROM myTable
WHERE idx2 IN (4,5,6);
Редактировать: Я знаю, что вы сказали, что знали, что это можно сделать с помощью UNION, но вам было важно выяснить, какие строки были найдены при каждом условии.
Приведенное выше решение должно удовлетворить ваше требование, чтобы столбец "other" отображался как NULL, потому что мы можем явно указать NULL в списке выбора вместо того, чтобы называть другой столбец.
Вы должны определить псевдонимы столбцов в первом запросе в UNION. Имена столбцов последующих запросов в UNION будут использовать псевдонимы столбцов, определенные в первом запросе.
Комментарии от @Kaii:
Оптимизация слияния индексов не помогает так часто, как вы могли ожидать. Вот демоверсия, протестированная на MySQL 8.0.14:
CREATE TABLE `mytable` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`idx1` int(11) DEFAULT NULL,
`idx2` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`),
KEY `idx1` (`idx1`),
KEY `idx2` (`idx2`)
);
Я заполнил его 1M + строками, со случайными значениями от 0 до 50 для idx1 и idx2.
select count(*) from mytable;
+----------+
| count(*) |
+----------+
| 1048576 |
+----------+
Запрос, использующий OR
, не выполняет слияние индексов, он выполняет сканирование таблицы (type=ALL
):
explain SELECT idx1, idx2 FROM myTable WHERE idx1 IN(1,2,3) OR idx2 IN(4,5,6);
+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| 1 | SIMPLE | myTable | NULL | ALL | idx1,idx2 | NULL | NULL | NULL | 1046577 | 51.00 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------+
Тогда как мое решение с UNION
использует оба индекса и не использует временную таблицу:
explain SELECT idx1, NULL AS idx2 FROM myTable WHERE idx1 IN (1,2,3) UNION ALL SELECT NULL, idx2 FROM myTable WHERE idx2 IN (4,5,6);
+----+-------------+---------+------------+-------+---------------+------+---------+------+--------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+-------+---------------+------+---------+------+--------+----------+--------------------------+
| 1 | PRIMARY | myTable | NULL | range | idx1 | idx1 | 5 | NULL | 113264 | 100.00 | Using where; Using index |
| 2 | UNION | myTable | NULL | range | idx2 | idx2 | 5 | NULL | 112678 | 100.00 | Using where; Using index |
+----+-------------+---------+------------+-------+---------------+------+---------+------+--------+----------+--------------------------+
Я профилировал оба запроса и обнаружил, что запрос UNION
в этом случае немного быстрее.
show profiles;
+----------+------------+-----------------------------------------------------------------------------------------------------------------------------+
| Query_ID | Duration | Query |
+----------+------------+-----------------------------------------------------------------------------------------------------------------------------+
| 1 | 0.22477500 | SELECT idx1, idx2 FROM myTable WHERE idx1 IN(1,2,3) OR idx2 IN(4,5,6) |
| 2 | 0.05573200 | SELECT idx1, NULL AS idx2 FROM myTable WHERE idx1 IN (1,2,3) UNION ALL SELECT NULL, idx2 FROM myTable WHERE idx2 IN (4,5,6) |
+----------+------------+-----------------------------------------------------------------------------------------------------------------------------+