Mariadb Сканирует все разделы в столбце отметки времени - PullRequest
0 голосов
/ 14 февраля 2020

У меня есть таблица, разделенная на:

HASH(timestamp DIV 43200 )

Когда я выполняю этот запрос

SELECT max(id) 
  FROM messages 
 WHERE timestamp BETWEEN 1581708508 AND 1581708807

, он сканирует все разделы, в то время как оба числа 1581708508 & 1581708807 и числа между ними находятся в одном разделе, как мне сделать так, чтобы он сканировал только этот раздел?

Ответы [ 2 ]

0 голосов
/ 22 февраля 2020

Вы обнаружили одну из причин, по которой сыворотка PARTITION BY HASH бесполезна.

В вашей ситуации Оптимизатор видит диапазон (BETWEEN) и говорит: «Пунт, я просто просканирую все разделы». ".

То есть" удаление разделов "не работает, если в предложении WHERE указан диапазон и вы используете PARTITION BY HASH. PARTITION BY RANGE, с другой стороны, может быть в состоянии обрезать. Но ... В чем преимущество? Это не делает запрос быстрее.

Я нашел только четыре варианта использования для разбиения: http://mysql.rjweb.org/doc.php/partitionmaint. Похоже, ваше приложение не подходит ни к одному из этих случаев.

Этот конкретный запрос лучше всего выполнить без разбиения. Вместо этого создайте однораздельную таблицу с этим «составным» индексом:

INDEX(timestamp, id)

. Она должна просканировать всю строку, чтобы обнаружить MAX(id), но с этим индексом это

  • Сканирование только по 2-столбцовому указателю
  • Не касаясь строк за пределами диапазона отметок времени.

Следовательно, это будет максимально быстро. Даже если бы PARTITION BY HASH был достаточно умен, чтобы выполнить желаемое сокращение, он не работал бы быстрее.

0 голосов
/ 15 февраля 2020

Вы можете определить этот отдельный раздел, используя модульную арифметику c

MOD(<formula which's argument of hash function>,<number of partitions>)

при условии, что у вас есть 2 раздела

CREATE TABLE messages(ID int, timestamp int)
PARTITION BY HASH( timestamp DIV 43200 )
PARTITIONS 2;

поиск имен разделов по

SELECT CONCAT( 'p',MOD(timestamp DIV 43200,2)) AS partition_name, timestamp 
  FROM messages;

и определите имя связанного раздела для значения 1581708508 столбца метки времени (предположим, p1). Затем используйте

SELECT MAX(id) 
  FROM messages PARTITION(p1)

, чтобы получить все записи только в разделе p1 без необходимости условия WHERE, такого как

WHERE timestamp BETWEEN 1581708508 AND 1581708807

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

SELECT * 
  FROM INFORMATION_SCHEMA.PARTITIONS 
 WHERE table_name='messages'

Демо

...