2016-05-19 4 views
1

я пытаюсь проверить преимущество секционирования в MysqlПочему MySQL разделение не имеет никакого эффекта в моем случае

Я создал две таблицы: одна распределяли другой нет.

В каждом столе есть 10M записей в нем.

Я хочу быстро запросить "user_to_id" column.

Разделенный стол (1024 части):

CREATE TABLE `neworder10M_part_byuser` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `site_from_id` int(11) NOT NULL, 
    `site_to_id` int(11) NOT NULL, 
    `user_from_id` int(11) NOT NULL, 
    `user_to_id` int(11) NOT NULL, 
    `created` datetime NOT NULL, 
    PRIMARY KEY (`id`,`user_to_id`), 
    KEY `composite_cover` (`user_to_id`,`user_from_id`,`site_from_id`,`site_to_id`,`created`) 
) ENGINE=InnoDB 
/*!50100 PARTITION BY HASH (user_to_id) 
PARTITIONS 1024 */ | 

Таблица с кластерным ключом (не секционированный):

CREATE TABLE `neworder_10M` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `site_from_id` int(11) NOT NULL, 
    `site_to_id` int(11) NOT NULL, 
    `user_from_id` int(11) NOT NULL, 
    `user_to_id` int(11) NOT NULL, 
    `created` datetime NOT NULL, 
    PRIMARY KEY (`user_to_id`,`id`), 
    UNIQUE KEY `id_UQ` (`id`) 
) ENGINE=InnoDB; 

, когда я тест обе таблицы с питона сценарием для 1000 Reqs:

for i in xrange(1,REQS): 
    user_id = random.randint(1,10000); 
    cursor.execute("select * from neworder10M_part_byuser where user_to_id=%s;" % (user_id)) 

Таблица разделов: 22 об/мин Не секционировано: 22,7 об./Мин

Почему нет преимущества скорости с секционированной таблицей? Поскольку я ожидаю, что меньшие данные - более быстрый запрос.

И объяснить также показывает, что раздел используется:

mysql> explain select * from neworder10M_part_byuser where user_to_id=6867; 
+----+-------------+-------------------------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------------+ 
| id | select_type | table     | partitions | type | possible_keys | key    | key_len | ref | rows | filtered | Extra  | 
+----+-------------+-------------------------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------------+ 
| 1 | SIMPLE  | neworder10M_part_byuser | p723  | ref | composite_cover | composite_cover | 4  | const | 1009 | 100.00 | Using index | 
+----+-------------+-------------------------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------------+ 

, но я не видел реальную скорость улучшения в реальности .... что я делаю неправильно?

таблицы заполнить код:

def send_orders(cur,users=10000,orders=10000000): 
    for i in xrange(1,orders+1): //10000000 rows here 
     print i 
     from_user = random.randint(1,users) 
     to_user = random.randint(1,users) 
     from_site = random.randint(1,10000) 
     to_site = random.randint(1,10000) 
     cur.execute("INSERT INTO neworder (site_from_id, site_to_id,user_from_id, user_to_id,created) VALUES ('%d','%d','%d','%d',NOW());" % (from_user,to_user,from_site,to_site)) 

версия MySQL: Ver 14.14 DISTRIB 5.7.12 для Linux (x86_64). Жесткий диск - ssd.

ответ

0

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

Без обрезки разделов мы ожидаем, что будет медленнее производительность с SELECT против секционированной таблицы. Так как это будет 1024 индекса, которые нужно проверить по сравнению с одним индексом.

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

+0

«Мы не ожидаем большой разницы в производительности для операторов SELECT», почему? как я понимаю по ключу раздела, можно определить раздел pXXX для O (1) времени, а затем сканировать только одно определенное разбиение на разделы быстрее, потому что индекс содержит 10K строк и 10M строк индекса таблицы без разделов. Почему индекс времени сканирования на 10K строк равен индексу сканирования на 10-миллиметровых строках? – Evg

+0

Потому что он не выполняет * полное * сканирование каждой записи индекса. Индекс организован таким образом, который позволяет механизму хранения очень быстро сужать на блоках, которые могут содержать записи, которые он ищет. С индексом есть огромные полосы блоков, которые невозможно для записей. Вот как работают индексы. Что касается размещения записей, не имеет значения, есть ли 10 000 блоков или 10 000 000 блоков, которые не нужно проверять. Вот почему производительность одинакова. – spencer7593

+0

«Не имеет значения, есть ли 10 000 блоков или 10 000 000 блоков, которые не нуждаются в проверке. Именно поэтому производительность - это то же самое« I Mysql ». Я думаю, что это неверный оператор. Индекс использует b + деревья.). Я просто тестирую таблицу на 100 тыс. Строк и получаю 1215 рпс против 20 рпс на таблице строк 10М. Таким образом, поиск в разделе с 10 тыс. Строк будет намного быстрее, чем 100 КБ, и намного больше, чем с 10 М. – Evg

0

(Это и ответ на вопрос и опровержение некоторых замечаний.)

Если пункт WHERE может вызвать раздел обрезку, чтобы это произошло, то это может помочь сделать составной индекс эффективной. Следовательно, нет преимущества перед несегментированной таблицей, учитывая, что вы можете выбрать лучший индекс.

Подумайте об обрезке разделов, уменьшив глубину глубины на 1 уровень. Но тогда вы должны сделать обрезку. Результат: практически такая же стоимость. Это мой ответ на вопрос о «сканировании диапазона на 10-миллиметровых рядах без разбивки по 10 тыс. Строк в одном разделе». (Ответы @ spencer7593 тоже хороши.)

Есть только 4 варианта использования, которые я нашел там, где PARTITIONing повышает производительность.Есть в my blog.

BY RANGE - единственный полезный метод разбиения. BY HASH, который вы используете, кажется совершенно бесполезным. В частности, если вы выполняете сканирование диапазона на «ключ раздела», он обязательно сканирует все разделы - нет «обрезки».

Обычно неэффективно класть ключ раздела первым в любую клавишу.

UNIQUE KEY id_UQ (id) - сделать это простой INDEX для вашего теста без разбивки; он будет более эффективным. И этого будет достаточно для обработки AUTO_INCREMENT.

(К сожалению, @ spencer7593 уже сказал, что некоторые из этих вещей, и указал на мой блог. Спасибо. Я написал это, потому что я устаю повторять себя на форумах.)

Ваш конкретный запрос (SELECT ... WHERE user_to_id = constant) является хороший способ продемонстрировать, насколько бесполезным является PARTITIONing (любого рода). Это ваш реальный запрос? На самом деле у вас могут быть другие запросы, которые могут извлечь выгоду из раздела; посмотрим на них.

«50 раз быстрее на меньшем столе» - кеширование? Стоит ли меньшая таблица в buffer_pool, но чем больше нет? I/O - самый большой фактор производительности.

Если WHERE user_to_id = constant всегда находится в ваших запросах, то в таблице не указывается user_to_id как первый столбец в каждом индексе (кроме INDEX(id)). Подумайте об этом как о «обрезке».