У меня проблема с оптимизацией довольно большой таблицы (~ 1,7 млн строк).
При выборе строк используются два столбца, назовем их colA и colB. Они оба имеют тип 'double' (5 десятичных знаков) и варьируются от:
колА: -90 ~ 90
colB: -180 ~ 180
Без индекса любой запрос вида:
SELECT * FROM table where colA BETWEEEN a and b AND colB BETWEEN c and d
Для выполнения
требуется примерно одинаковое время (~ 1 секунда), независимо от диапазона (a, b) и (c, d) (поскольку MySQL должен проверять каждую строку).
Если я добавлю индекс к colA и colB, произойдут две вещи: запросы, в которых диапазон (a, b) и (c, d) мал, например:
SELECT * FROM table where colA BETWEEEN -4 and 4 AND colB BETWEEN 3 and 7
бегать очень быстро (~ 1/10 секунды). Однако время выполнения увеличивается с увеличением диапазона между запрашиваемыми значениями. Например:
SELECT * FROM table where colA BETWEEEN -80 and 80 AND colB BETWEEN -150 and 150
выполнение занимает около минуты.
Я знаю, как B-деревья работают со строками, но я не уверен в механизме, когда данные являются числовыми, а запрос выполняется с использованием диапазона.
Если бы кто-нибудь мог подсказать, как оптимизировать этот запрос, я был бы благодарен. Одна мысль состоит в том, чтобы использовать индекс для небольших диапазонов и запретить MySQL использовать его для больших диапазонов, однако я не смог найти команду, которая позволяет это.
Спасибо
РЕДАКТИРОВАТЬ: объясняет
Есть кое-что, что я тупо забыл упомянуть. Результаты упорядочены по rand () - я знаю, насколько это неэффективно, но я не мог найти другого способа получить произвольно ограниченное количество строк из таблицы.
Добавление rand () не влияет на время выполнения, когда нет индекса, но резко увеличивает время, необходимое, когда оно есть.
EDIT2: это использование составных индексов.
МАЛЫЙ ДИАПАЗОН:
"объяснить выбор * из таблицы, где colA между 35 и 38 и colB между -10 и 5 ORDER BY RAND () LIMIT 20"
9783 строки
NO INDEX (быстрый)
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| 1 | SIMPLE | table | ALL | NULL | NULL | NULL | NULL | 1673784 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
С ИНДЕКСОМ (очень быстро)
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | table | range | test | test | 18 | NULL | 136222 | Using where |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
БОЛЬШОЙ ДИАПАЗОН:
"объяснить выбор * из таблицы, где colA между -80 и 80 и colB между -150 и 150 ORDER BY RAND () LIMIT 20;"
1631862 строк
NO INDEX (быстрый)
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| 1 | SIMPLE | table | ALL | NULL | NULL | NULL | NULL | 1673784 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
С ИНДЕКСОМ (очень медленно:> 60 секунд)
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| 1 | SIMPLE | table | ALL | test | NULL | NULL | NULL | 1673784 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
EDIT3:
Подводя итог: (все запросы ограничены возвращением 20 строк)
большой диапазон с rand () с индексом: 45 секунд
большой диапазон без ранда (), с индексом: 0,003 секунды
большой диапазон с рандом, без индекса: 1 секунда
большой диапазон без ранда, без индекса: 0,003 секунды
Аномалия: «большой диапазон с rand () с индексом, 45 секунд».