Разделение MySQL: разделы вне диапазона дат включены - PullRequest
1 голос
/ 19 марта 2010

Я только что попытался настроить разделы на основе даты, но похоже, что MySQL по-прежнему включает раздел без соответствующих данных. Он будет использовать соответствующие раздел, но также включают в себя самый старый по некоторым причинам. Я делаю это неправильно?

Версия 5.1.44 (MyISAM)

Сначала я добавил несколько разделов на основе "дня", который имеет тип "дата"

ALTER TABLE ptest
PARTITION BY RANGE(TO_DAYS(day))
(
PARTITION p1 VALUES LESS THAN (TO_DAYS('2009-08-01')),
PARTITION p2 VALUES LESS THAN (TO_DAYS('2009-11-01')),
PARTITION p3 VALUES LESS THAN (TO_DAYS('2010-02-01')),
PARTITION p4 VALUES LESS THAN (TO_DAYS('2010-05-01'))
);

После запроса я обнаружил, что он использует «старый» раздел, который не должен содержать никаких соответствующих данных.

mysql> explain partitions select * from ptest where day between '2010-03-11' and '2010-03-12';
+----+-------------+------------+------------+-------+---------------+------+---------+------+------+-------------+
| id | select_type | table      | partitions | type  | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+------------+------------+-------+---------------+------+---------+------+------+-------------+
| 1  | SIMPLE      | ptest      | p1,p4      | range | day           | day  | 3       | NULL | 79   | Using where |
+----+-------------+------------+------------+-------+---------------+------+---------+------+------+-------------+

Когда я выбираю один день, он работает как положено:

mysql> explain partitions select * from ptest where day = '2010-03-11';
+----+-------------+------------+------------+------+---------------+------+---------+-------+------+-------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref   | rows | Extra |
+----+-------------+------------+------------+------+---------------+------+---------+-------+------+-------+
| 1  | SIMPLE      | ptest      | p4         | ref  | day           | day  | 3       | const | 39   |       |
+----+-------------+------------+------------+------+---------------+------+---------+-------+------+-------+

Ответы [ 2 ]

2 голосов
/ 21 июня 2011

Это на самом деле ожидаемый результат, потому что самый старый раздел всегда будет содержать значения, которые не были оценены до допустимой даты (ноль). Обходной путь для этого - создать дополнительный раздел, который не будет содержать данных и будет существовать для всех значений до самой старой даты. Этот раздел всегда будет сканироваться, но он мало влияет на производительность, поскольку он пустой.

http://bugs.mysql.com/bug.php?id=49754

1 голос
/ 19 марта 2010

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

Вы должны будете сделать, например, выберите * из ptest, где день между TO_DAYS ('2010-03-11') и TO_DAYS ('2010-03-12') - хотя в этом случае могут быть недостатки в mysql между.

Разделение по датам в mysql сложно, и в реализации разделения есть много недостатков, по крайней мере, если вы хотите охватить множество различных ограничений запроса, мы обычно помещаем целочисленный идентификатор в таблицы, указывающие на календарь вместо тип DATE, поскольку мы обнаружили, что mysql для обработки разбиения по простому целому числу достаточно надежен по сравнению с разбиением по столбцам с функцией (такой как TO_DAYS), мы имеем

create table datatbl (
  time_id int NOT NULL,
  ....
);

time_id ссылается на календарь, заполненный датами на следующие 10 лет, в виде

create table calendar (
  time_id int primary key
  year int NOT NULL,
  month int NOT NULL,
  day int NOT NULL,
  dayofyear int NOT NULL,
  quarter int NOT NULL,
  is_weekend char(1) NOT NULL,
  db_date DATE not NULL,
  unique index(year,month,day),
  unique index(dbdate)
);

Запросы объединяются в эту таблицу, поэтому для получения всех данных за месяц требуется where cal.year = 2010 and cal.month = 1. Или это можно сделать как cal.db_date between '2010-01-01' and '2010-01-31'

datatbl разделен на time_id, и вышеупомянутые запросы заставят mysql делать сокращение секционирования. time_id также является составной частью года / месяца / даты, поэтому time_id для 2010-03-03 будет целым числом 20100303, которое не следует использовать для запроса, это просто удобство для сценариев, которые автоматически создают new / drop старые разделы.

...