MYSQL: нужна помощь для быстро растущей таблицы и снижения скорости (4 миллиона строк) - PullRequest
4 голосов
/ 19 мая 2011

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

Настройка:

    Intel i7 720 
    8GB RAM
    2x750GB SATA RAID 0
    CentOS
    MySQL 5.5.10
    Node.js + node-lib_mysql-client

Определение таблицы:

CREATE TABLE IF NOT EXISTS `canvas` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`x1` int(11) NOT NULL,
`y1` int(11) NOT NULL,
`x2` int(11) NOT NULL,
`y2` int(11) NOT NULL,
`c` int(4) unsigned NOT NULL,
`s` int(3) unsigned NOT NULL,
`m` bigint(20) unsigned NOT NULL,
`r` varchar(32) NOT NULL,
PRIMARY KEY (`id`,`x1`,`y1`) KEY_BLOCK_SIZE=1024,
KEY `x1` (`x1`,`y1`) KEY_BLOCK_SIZE=1024,
KEY `x2` (`x2`,`y2`) KEY_BLOCK_SIZE=1024
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=4
/*!50100 PARTITION BY HASH ( (
(
x1 MOD 10000
)
) + y1 MOD 10000)
PARTITIONS 10 */ AUTO_INCREMENT=13168904 ;

Запрос:

SELECT x1,y1,x2,y2,s,c,r,m FROM canvas
WHERE 1 AND ((
 x1 >= 0
 AND x1 <= 400
 AND y1 >= 0
 AND y1 <= 400
 ) OR ( 
 x2 >= 0
 AND x2 <= 400
 AND y2 >= 0
 AND y2 <= 400
 ) )
  ORDER BY id desc

Это единственный запрос, который я выполняю, за исключением того факта, что значения x1, y1, x2 и y2 меняются в каждом запросе. Это 2D холст, и каждая строка представляет линию на холсте. Думаю, также важно знать, что максимальный диапазон, выбранный для 1 поля, никогда не превышает 1200 (пикселей). Несколько недель назад я обновился до MySQL 5.5.10 и начал использовать разделы. Хэш 'x1% 10000' - мой первый и неосведомленный подход к теме раздела. Это уже дало мне приличный прирост скорости SELECT, но я уверен, что еще есть место для оптимизации.

Да, и прежде чем вы спросите ... Я знаю, что я использую таблицу MyISAM. Мой друг предложил innoDB, но уже попробовал, и в результате получилось увеличение таблицы в 2 раза и падение производительности SELECT. Мне не нужны никакие причудливые транзакции и прочее ... все, что мне нужно, это наилучшая возможная производительность SELECT и достойная производительность с INSERT.

Что бы вы изменили? Могу ли я как-нибудь настроить свои индексы? Имеет ли смысл установка моих разделов вообще? Должен ли я, возможно, увеличить количество файлов разделов?

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

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

Спасибо, что читаете и думаете об этом. :)

РЕДАКТИРОВАТЬ: Запрошенный результат EXPLAIN

select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
SIMPLE  canvas  index_merge     x1,x2   x1,x2   8,8     NULL    133532  Using sort_union(x1,x2); Using where; Using fileso...

EDIT2: запрошенный my.cnf

[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

innodb_buffer_pool_size = 1G
sort_buffer_size = 4M
read_buffer_size = 1M
read_rnd_buffer_size = 16M
innodb_file_format = Barracuda

query_cache_type = 1
query_cache_size = 100M

# http://dev.mysql.com/doc/refman/5.5/en/performance-schema.html
;performance_schema


[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

Значения innoDB для моей попытки innoDB ... думаю, они больше не нужны. Сервер также управляет 4 другими веб-сайтами, но они довольно малы и не заслуживают упоминания. Я все равно скоро перенесу этот проект в специальную коробку. Ваши идеи могут быть радикальными - я не против экспериментов.

EDIT3 - ЭТАЛОНЫ С ИНДЕКСАМИ

Хорошо, ребята ... Я сделал несколько тестов с разными индексами, и результаты пока довольно хорошие. Для этого теста я выбрал все строки в блоке размером 2000x2000 пикселей.

SELECT SQL_NO_CACHE x1,y1,x2,y2,s,c FROM canvas_test WHERE 1 AND (( x1 BETWEEN -6728 AND -4328 AND y1 BETWEEN -6040 AND -4440 ) OR (  x2 BETWEEN -6728 AND -4328 AND y2 BETWEEN -6040 AND -4440 ) )  ORDER BY id asc

Используя определение таблицы / индекса, которое я разместил выше, среднее время запроса было: 1740ms

Затем я отбросил все индексы, кроме первичного ключа -> 1900ms

добавлен один индекс для x1 -> 1800 мс

добавлен один индекс для y1 -> 1700 мс

добавлен один индекс для x2 -> 1500 мс

добавлен один индекс для y2 -> 900 мс!

Пока что это удивительно ... почему-то я думал, что создание комбинированных индексов для x1 / y1 и x2 / y2 имело бы смысл, но на самом деле это выглядит так, как будто я ошибался.

EXPLAIN теперь возвращает это:

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   SIMPLE  canvas_test     index_merge     x1,y1,x2,y2     y1,y2   4,4     NULL    263998  Using sort_union(y1,y2); Using where; Using fileso..

Теперь мне интересно, почему он использует y1 / y2 в качестве ключей, а не все четыре?

Однако я все еще ищу больше идей и советов, особенно относительно разделов и правильного хеширования.

Ответы [ 4 ]

2 голосов
/ 19 мая 2011

Во-первых, я бы изменил SELECT как

SELECT x1,y1,x2,y2,s,c,r,m FROM canvas
WHERE 
  x1 BETWEEN 0 AND 400 AND y1 BETWEEN 0 AND 400 OR
  x2 BETWEEN 0 AND 400 AND y2 BETWEEN 0 AND 400
ORDER BY id desc

И также обязательно имел бы индекс этого выражения:

CREATE INDEX canvas400 ON canvas(
  x1 BETWEEN 0 AND 400 AND y1 BETWEEN 0 AND 400 OR
  x2 BETWEEN 0 AND 400 AND y2 BETWEEN 0 AND 400
)
1 голос
/ 03 августа 2011

Помните, что MySQL будет использовать только один индекс на таблицу для каждого запроса. Ваш запрос SELECT не сможет использовать оба ваших индекса в одном запросе - он будет использовать один или другой. Вы можете обнаружить, что более эффективно объединять два запроса SELECT вместе, чтобы каждый мог использовать соответствующий индекс, например:

SELECT x1,y1,x2,y2,s,c,r,m FROM canvas
WHERE 
 x1 >= 0
 AND x1 <= 400
 AND y1 >= 0
 AND y1 <= 400
UNION
SELECT x1,y1,x2,y2,s,c,r,m FROM canvas
WHERE
 x2 >= 0
 AND x2 <= 400
 AND y2 >= 0
 AND y2 <= 400
;

или вы можете использовать МЕЖДУ, как один из предложенных ответов, например:

SELECT x1,y1,x2,y2,s,c,r,m FROM canvas
WHERE x1 BETWEEN 0 AND 400 AND y1 BETWEEN 0 AND 400
UNION
SELECT x1,y1,x2,y2,s,c,r,m FROM canvas
WHERE x2 BETWEEN 0 AND 400 AND y2 BETWEEN 0 AND 400
;

Уже давно я использую UNION, поэтому я не уверен, куда вы поместите предложение ORDER BY, но вы можете поэкспериментировать с этим.

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

Возможно, стоит также посмотреть индекс RTREE, хотя я сам с ними не играл.

1 голос
/ 19 мая 2011
  1. Сколько памяти использует ваш сервер в настоящее время?
  2. Это единственная база данных / таблица на сервере?
  3. Вы используете исключительно MyISAM?

MyISAM можно использовать, если вы не обновляете свои строки. Когда вы обновляете строку в таблице MyISAM, MySQL блокирует всю таблицу, блокируя выполнение любых команд SELECT и INSERTS до тех пор, пока не завершится ОБНОВЛЕНИЕ. UPDATE имеет приоритет над SELECT, поэтому, если у вас запущено много UPDATE, ваши SELECTS будут ждать, пока все они не будут завершены, прежде чем они вернут какие-либо строки.

Если с вами все в порядке, перейдите к конфигурации вашего сервера. Как выглядит ваш файл my.cnf? Вы захотите оптимизировать этот файл, чтобы максимально увеличить объем памяти, который вы можете использовать для индексов. Если эти SELECT замедляются, это потому, что индексы вашей таблицы не помещаются в памяти. Если MySQL не может разместить ваши табличные индексы в памяти, он должен перейти на диск и выполнить сканирование таблицы, чтобы получить ваши данные. Это убьет производительность.

РЕДАКТИРОВАНИЕ 18.05.2011 21:30 EST

После просмотра вашего my.cnf я заметил, что у вас есть ноль оптимизаций MyISAM. Ваше начальное место будет переменной key_buffer_size. Эта переменная, как правило, устанавливается где-то между 25% и 50% от общей доступной памяти в вашей системе. В вашей системе доступно 8 ГБ памяти, поэтому я бы сказал, что где-то около 3 ГБ является минимальной отправной точкой. Тем не менее, вы можете оценить, сколько вам потребуется, и оптимизировать его по мере необходимости, если знаете, что имеете контроль над другими переменными в системе.

Что вам нужно сделать, это перейти к вашему каталогу данных mysql (обычно /var/lib/mysql), где находятся все ваши файлы данных. Быстрый способ узнать, сколько у вас есть индексных данных

 sudo du -hc `find . -type f -name "*.MYI"

Эта команда проверит размер всех ваших файлов индекса MyISAM и сообщит вам их общий размер. Если у вас достаточно памяти, вы хотите, чтобы ваш key_buffer_size в my.cnf был БОЛЬШЕ, чем общий размер всех ваших файлов MYI. Это гарантирует, что ваши индексы MyISAM находятся в памяти, поэтому MySQL не нужно будет обращаться к диску для данных индекса.

Небольшая заметка, не увеличивайте свой key_buffer_size волей и неволей. Это только одна область MySQL, которая нуждается в памяти, есть другие движущиеся части, с которыми вам нужно сбалансировать использование памяти. Соединения MySQL занимают память, и разные движки таблиц используют разные пулы памяти для своих индексов, а MySQL использует другие биты памяти для разных целей. Если вам не хватит памяти, потому что вы установили key_buffer_size слишком большим, ваш сервер может начать подкачку (используя виртуальную память, которая убьет производительность даже БОЛЬШЕ) или, что еще хуже, произойдет сбой. Начните с меньших значений, если вы не уверены, проверьте использование памяти и увеличивайте ее до тех пор, пока не будете удовлетворены производительностью, и ваш сервер не выйдет из строя.

0 голосов
/ 19 мая 2011

Какие скорости вы получаете?Поскольку вам не нужны никакие реляционные данные, вам следует рассмотреть возможность перемещения данных в Redis , поэтому на вашем компьютере должно быть легко вставлено + 100 тыс. Вставок или операций чтения / сек.

...