Проблемы с получением разделов, чтобы изменить время запроса - PullRequest
0 голосов
/ 03 мая 2019

Я просто немного экспериментирую с разделами с некоторыми фиктивными данными, и пока мне не удаётся оптимизировать свои запросы.

Я скачал набор данных из Интернета, который состоит из одной таблицыmeasurements:

CREATE TABLE `partitioned_measures` (
  `measure_timestamp` datetime NOT NULL,
  `station_name` varchar(255) DEFAULT NULL,
  `wind_mtsperhour` int(11) NOT NULL,
  `windgust_mtsperhour` int(11) NOT NULL,
  `windangle` int(3) NOT NULL,
  `rain_mm` decimal(5,2) DEFAULT NULL,
  `temperature_dht11` int(5) DEFAULT NULL,
  `humidity_dht11` int(5) DEFAULT NULL,
  `barometric_pressure` decimal(10,2) NOT NULL,
  `barometric_temperature` decimal(10,0) NOT NULL,
  `lux` decimal(7,2) DEFAULT NULL,
  `is_plugged` tinyint(1) DEFAULT NULL,
  `battery_level` int(3) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
/*!50100 PARTITION BY RANGE (TO_DAYS(measure_timestamp))
(PARTITION `slow` VALUES LESS THAN (736634) ENGINE = InnoDB,
 PARTITION `fast` VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */

Так же, как учебное упражнение Я хотел попытаться разделить измерения на measure_timestamp (без помощи индексации).В частности, я подумал, что было бы интересно попытаться поместить самый последний месяц в отдельный раздел.(Я понимаю, что лучше иметь разделы одинакового размера, но я просто хотел поэкспериментировать)

Я использовал следующую команду для добавления раздела (Обратите внимание, что набор данных заканчивается в декабре 2016 года, и подавляющее большинствоиз точек данных за предыдущие месяцы):

ALTER TABLE partitioned_measures 
    PARTITION BY RANGE(TO_DAYS(measure_timestamp)) (
        PARTITION slow VALUES LESS THAN(TO_DAYS('2016-12-01')), 
        PARTITION fast VALUES LESS THAN (MAXVALUE)
    );

Для запроса я просматриваю все записи, начиная со 2-го и последующих (просто чтобы убедиться, что я смотрю только в последнем разделе):

select SQL_NO_CACHE COUNT(*) FROM partitioned_measures 
    WHERE measure_timestamp >= '2016-12-02' 
    AND DAYOFWEEK(measure_timestamp) = 1;

Когда я добавляю EXPLAIN к началу, я получаю следующее:

+----+-------------+----------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table                | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+----------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | partitioned_measures | slow,fast  | ALL  | NULL          | NULL | NULL    | NULL | 1835458 |    33.33 | Using where |
+----+-------------+----------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+

Но время запроса примерно такое же, как и до раздела (~1,6 секунды).Я никогда раньше не использовал разделы, поэтому я чувствую, что есть что-то концептуальное, что мне не хватает.

Ответы [ 2 ]

1 голос
/ 04 мая 2019

Объяснение:

Он сделал , что вы запросили обрезку, но он добавил первый раздел. Зачем? Потому что там плохие даты.

Обходной путь должен иметь фиктивный первый раздел:

/*!50100 PARTITION BY RANGE (TO_DAYS(measure_timestamp))
({ARTITION bogus  VALUES LESS THAN (0)      ENGINE = InnoDB,   -- any small value
 PARTITION `slow` VALUES LESS THAN (736634) ENGINE = InnoDB,
 PARTITION `fast` VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */

Ссылка похоронена в https://dev.mysql.com/doc/refman/5.7/en/partitioning-handling-nulls.html

Если бы у вас было больше тривиального числа разделов, вы могли бы быть более очевидными, если бы он выбрал нужный раздел, плюс всегда первый.

За редкими исключениями секционирование не обеспечивает лучшую производительность, чем вы можете получить из однораздельной таблицы с подходящим индексом. В этом случае INDEX(measure_timestamp). (Или виртуальный столбец с INDEX(dow, measure_timestamp).)

1 голос
/ 03 мая 2019

Сложно, но я нашел рабочее решение, или я должен сказать, что это обходной путь, это похоже на ошибку MySQL?

   ALTER TABLE partitioned_measures 
    PARTITION BY RANGE COLUMNS(measure_timestamp) (
        PARTITION slow VALUES LESS THAN('2016-12-01'), 
        PARTITION fast VALUES LESS THAN(MAXVALUE)
    );

см. demo , который правильно использует сокращение раздела

я заметил, что синтаксис здесь

Я все еще нахожу его странным, что разделение на части не работает правильно, с

    ALTER TABLE partitioned_measures 
    PARTITION BY RANGE(TO_DAYS(measure_timestamp)) (
        PARTITION slow VALUES LESS THAN(TO_DAYS('2016-12-01')), 
        PARTITION fast VALUES LESS THAN (MAXVALUE)
    );

MySQL 5.7 должен быть в состояниивыполните сокращение секционирования, которое TO_DAYS() очень хорошо

Сокращение может также применяться к таблицам, секционированным в столбце DATE или DATETIME, когда выражение секционирования использует функцию YEAR () или TO_DAYS ().Кроме того, в MySQL 5.7

source

см. demo , который не использует правильное сокращение разделов, я пробовал много , чтобы заставить его работать, все методы потерпели неудачу, о которой я мог подумать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...