MySQL выбирает определенные столбцы медленнее, чем select * - PullRequest
4 голосов
/ 04 июня 2010

Мой MySQL не силен, поэтому, пожалуйста, простите любые ошибки новичка. Короткая версия:

SELECT locId, count, avg ОТ destAgg_geo значительно медленнее, чем SELECT * из destAgg_geo

prtt.destAgg - таблица с ключом dst_ip (PRIMARY)

mysql> describe prtt.destAgg;
+---------+------------------+------+-----+---------+-------+
| Field   | Type             | Null | Key | Default | Extra |
+---------+------------------+------+-----+---------+-------+
| dst_ip  | int(10) unsigned | NO   | PRI | 0       |       |
| total   | float unsigned   | YES  |     | NULL    |       |
| avg     | float unsigned   | YES  |     | NULL    |       |
| sqtotal | float unsigned   | YES  |     | NULL    |       |
| sqavg   | float unsigned   | YES  |     | NULL    |       |
| count   | int(10) unsigned | YES  |     | NULL    |       |
+---------+------------------+------+-----+---------+-------+

geoip.blocks - таблица с ключами как startIpNum, так и endIpNum (PRIMARY)

mysql> describe geoip.blocks;
+------------+------------------+------+-----+---------+-------+
| Field      | Type             | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+-------+
| startIpNum | int(10) unsigned | NO   | MUL | NULL    |       |
| endIpNum   | int(10) unsigned | NO   |     | NULL    |       |
| locId      | int(10) unsigned | NO   |     | NULL    |       |
+------------+------------------+------+-----+---------+-------+

destAgg_geo - это вид:

CREATE VIEW destAgg_geo AS SELECT * FROM destAgg JOIN geoip.blocks 
  ON destAgg.dst_ip BETWEEN geoip.blocks.startIpNum AND geoip.blocks.endIpNum;

Вот план оптимизации для выбора *:

mysql> explain select * from destAgg_geo;
+----+-------------+---------+------+---------------+------+---------+------+---------+------------------------------------------------+
| id | select_type | table   | type | possible_keys | key  | key_len | ref  | rows    | Extra                                          |
+----+-------------+---------+------+---------------+------+---------+------+---------+------------------------------------------------+
|  1 | SIMPLE      | blocks  | ALL  | start_end     | NULL | NULL    | NULL | 3486646 |                                                |
|  1 | SIMPLE      | destAgg | ALL  | PRIMARY       | NULL | NULL    | NULL |  101893 | Range checked for each record (index map: 0x1) |
+----+-------------+---------+------+---------------+------+---------+------+---------+------------------------------------------------+

Вот план оптимизации для выбора с конкретными столбцами:

mysql> explain select locId,count,avg from destAgg_geo;
+----+-------------+---------+------+---------------+------+---------+------+---------+------------------------------------------------+
| id | select_type | table   | type | possible_keys | key  | key_len | ref  | rows    | Extra                                          |
+----+-------------+---------+------+---------------+------+---------+------+---------+------------------------------------------------+
|  1 | SIMPLE      | destAgg | ALL  | PRIMARY       | NULL | NULL    | NULL |  101893 |                                                |
|  1 | SIMPLE      | blocks  | ALL  | start_end     | NULL | NULL    | NULL | 3486646 | Range checked for each record (index map: 0x1) |
+----+-------------+---------+------+---------------+------+---------+------+---------+------------------------------------------------+

Вот план оптимизации для каждого столбца из destAgg и только столбца locId из geoip.blocks:

mysql> explain select dst_ip,total,avg,sqtotal,sqavg,count,locId from destAgg_geo;
+----+-------------+---------+------+---------------+------+---------+------+---------+------------------------------------------------+
| id | select_type | table   | type | possible_keys | key  | key_len | ref  | rows    | Extra                                          |
+----+-------------+---------+------+---------------+------+---------+------+---------+------------------------------------------------+
|  1 | SIMPLE      | blocks  | ALL  | start_end     | NULL | NULL    | NULL | 3486646 |                                                |
|  1 | SIMPLE      | destAgg | ALL  | PRIMARY       | NULL | NULL    | NULL |  101893 | Range checked for each record (index map: 0x1) |
+----+-------------+---------+------+---------------+------+---------+------+---------+------------------------------------------------+

Удалите все столбцы, кроме dst_ip и проверка диапазона переключается на блоки:

mysql> explain select dst_ip,avg,sqtotal,sqavg,count,locId from destAgg_geo;
+----+-------------+---------+------+---------------+------+---------+------+---------+------------------------------------------------+
| id | select_type | table   | type | possible_keys | key  | key_len | ref  | rows    | Extra                                          |
+----+-------------+---------+------+---------------+------+---------+------+---------+------------------------------------------------+
|  1 | SIMPLE      | destAgg | ALL  | PRIMARY       | NULL | NULL    | NULL |  101893 |                                                |
|  1 | SIMPLE      | blocks  | ALL  | start_end     | NULL | NULL    | NULL | 3486646 | Range checked for each record (index map: 0x1) |
+----+-------------+---------+------+---------------+------+---------+------+---------+------------------------------------------------+

что намного медленнее. Что здесь происходит?

(Да, я мог бы просто использовать * результаты запроса и обрабатывать их оттуда, но я хотел бы знать, что происходит и почему)

EDIT - ОБЪЯСНИТЬ по запросу VIEW:

mysql> explain SELECT * FROM destAgg JOIN geoip.blocks ON destAgg.dst_ip BETWEEN geoip.blocks.startIpNum AND geoip.blocks.endIpNum;
+----+-------------+---------+------+---------------+------+---------+------+---------+------------------------------------------------+
| id | select_type | table   | type | possible_keys | key  | key_len | ref  | rows    | Extra                                          |
+----+-------------+---------+------+---------------+------+---------+------+---------+------------------------------------------------+
|  1 | SIMPLE      | blocks  | ALL  | start_end     | NULL | NULL    | NULL | 3486646 |                                                |
|  1 | SIMPLE      | destAgg | ALL  | PRIMARY       | NULL | NULL    | NULL |  101893 | Range checked for each record (index map: 0x1) |
+----+-------------+---------+------+---------------+------+---------+------+---------+------------------------------------------------+

Ответы [ 3 ]

1 голос
/ 04 июня 2010

Фильтр диапазона применяется последним, поэтому проблема заключается в том, что оптимизатор запросов выбирает сначала объединение таблицы большего размера в одном случае, а сначала таблицы меньшего размера - в другом. Возможно, кто-то с большим знанием об оптимизаторе может сказать нам, почему он объединяет таблицы в различном порядке для каждого.

Я думаю, что реальная цель здесь должна состоять в том, чтобы попытаться заставить JOIN использовать индекс, чтобы порядок соединения не имел большого значения.

1 голос
/ 04 июня 2010

MySQL может сообщить вам, если вы выполняете EXPLAIN PLAN для обоих запросов.

Первый запрос со столбцами не включает ключевые столбцы, поэтому я предполагаю, что он должен выполнить TABLE SCAN.

Второй запрос с «SELECT *» включает первичный ключ, поэтому он может использовать индекс.

0 голосов
/ 04 июня 2010

Я бы попробовал поместить композитный индекс в locId, count, avg и посмотреть, не улучшит ли это скорость.

...