SQLinfo.ru - Все о MySQL

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 11.08.2009 13:43:55

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

долгий выбор данных

Есть таблица ~1-2 Гб, ~10 млн. записей, несколько десятков инсертов в секунду.

Пусть col_key - столбец, на котором есть ключ, col_data - где нет.

SELECT col_key FROM tbl WHERE col_key = N занимает сотые секунды (записей выбирается обычно несколько тысяч). Тут понятно, что сервер пользуется индексом и сразу оттуда берет.
SELECT col_data FROM tbl WHERE col_key = N занимает полминуты.
Тоже понятно, что лезет на диск и ищет там. Но чего ж так долго-то?

Можно ли как-то ускорить или уже предел?

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

Неактивен

 

#2 11.08.2009 18:46:19

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6756

Re: долгий выбор данных

Исамовская табличка, небось? Несколько тысяч сиков — это достаточно много.
Впрочем, тебе разве нужны все несколько тысяч? LIMIT нужно хвостиком сделать.

Ну и как вариант — сделать InnoDB (тем самым перевалив данные в ОЗУ), ну
или partitioning по col_key, тоже очень хорошо тут отработает.

Неактивен

 

#3 13.08.2009 01:59:21

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: долгий выбор данных

Не, табличка InnoDB.

Впрочем, тебе разве нужны все несколько тысяч? LIMIT нужно хвостиком сделать.

К сожалению, задача ставится так, что именно все несколько тысяч sad

Перечитал темы про организацию логов, да и другие некоторые. Хочу поделиться размышлениями.

I. MERGE/VIEW не подходит по следующим причинам:

1. Нужна уникальность ключа (даже нескольких, на самом деле). Я так понимаю, нормальных средств, позволяющих поддерживать уникальность на всем пространстве MERGE, не имеется.

2. С MERGE медленнее чтение по ключу. А чтение тоже периодически случается, причем иногда - по всей таблице (заказчик захотел динамическую статистику за сутки; в основном, конечно, данные добавляются и удаляются кусками, но встречаются и такие запросы, которые приходится делать на всю таблицу)

3. Все-таки в таблицу десятки инсертов в секунду. Несколько раз в минуту бывают и селекты. Как-то страшновато использовать MyISAM в таких условиях имхо.. (хотя лочиться будет только последняя таблица, все же не круто..)

II. Partitioning.

Основной вопрос здесь такой: как влияет paritioning на поиск по остальным ключам (кроме того, по которому разбиение)?
У меня часто задействуются другие ключи. Не будет ли там ситуации, такой же, как в MERGE, когда надо подряд все ключи во всех разделах обыскивать?

III. Еще вот такая идея: а что, если эту всю таблицу загнать в память? (т.е. сделать ей ENGINE = MEMORY)?..
И, например, снять часть ключей?
Насколько поиск по неотсортированной памяти медленнее поиска по отсортированной памяти?

Неактивен

 

#4 13.08.2009 13:19:52

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6756

Re: долгий выбор данных

А поглядеть можно на базку как-то? Очень странный эффект. Ну то есть
сходу в голову приходит только «col_data — большущий blob».

И еще вопрос. У тебя табличка 10кк строк, insertы по 10rps, т.е. всей таблице
2 недели жизни. А что с ней будет через 2 месяца? Или там что-то еще ее
меняет?

Неактивен

 

#5 13.08.2009 14:08:13

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: долгий выбор данных

А поглядеть можно на базку как-то?

Милости просим smile (не хотел эфир просто засорять)
Соответственно, col_key - это siteid, col_data - это refhost.

CREATE TABLE `brevno_ext_sessions` (
  `id` bigint(10) unsigned NOT NULL auto_increment,
  `siteid` int(10) unsigned NOT NULL,
  `uuid` char(36) NOT NULL,
  `DATE` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  `useragent` varchar(255) NOT NULL,
  `refhost` varchar(255) NOT NULL,
  `refuri` varchar(2048) NOT NULL,
  `GET` varchar(2048) NOT NULL default '',
  PRIMARY KEY  (`id`),
  KEY `uuid` (`uuid`),
  KEY `DATE` (`DATE`),
  KEY `siteid` (`siteid`)
) ENGINE=InnoDB AUTO_INCREMENT=5543800 DEFAULT CHARSET=latin1

Это сессии нескольких тысяч маленьких сайтов за сутки (т.е. записей где-то один-два миллиона; потом будет побольше).

Запрос вида SELECT refhost FROM brevno_ext_sessions WHERE siteid = N как раз и занимает полминуты.

(еще там вторая есть тоже большая, насчет неё уже жаловался:
http://sqlinfo.ru/forum/viewtopic.php?id=1316
так что если будет дежа вю - не удивляйся smile )

И еще вопрос. У тебя табличка 10кк строк, insertы по 10rps, т.е. всей таблице
2 недели жизни. А что с ней будет через 2 месяца? Или там что-то еще ее
меняет?

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

Неактивен

 

#6 13.08.2009 15:54:41

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: долгий выбор данных

Меня также не перестает интересовать следующее: как влияет paritioning на поиск по остальным ключам? smile

Неактивен

 

#7 13.08.2009 17:22:30

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6756

Re: долгий выбор данных

Уууу! Много независимых мыслей:

Считай, что это MERGE с возможностью PRUNING. Это очень близко к действительности.

По поводу запроса — я думал, что по site у тебя по крайней мере PK стоит wink Когда ты
делаешь SELECT siteid FROM brevno_ext_sessions WHERE siteid = 1 — у тебя работает
USING INDEX, более того, ему достаточно посчитать количество строк по индексу.
Когда ты тянешь данные, ему нужно сделать куда больше работы — найти по индексу
PK соответствующий, а по нему уже вытащить данные. Подозреваю, что «короткий»
запрос читает с диска 1-2 страницы последовательно (т.к. сортирован), а «длинный»
хорошо и жестко бегает в поисках этих 1000 страниц данных.

В MEMORY эта хреновина не влезет (см на varchar(2048) несколько раз).

Если uuid — это md5, то binary(16) гораздо лучше, чем char(36).

Подозреваю, что все запросы у тебя все-таки per-site, попробуй покластеризовать по
HASH(siteid) с каким-нибудь невменяемым количеством кусков типа 1000.

А кто вообще придумал хранить независимые данные по тысячам сайтов в одной табличке?

Неактивен

 

#8 13.08.2009 21:44:10

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: долгий выбор данных

Подозреваю, что все запросы у тебя все-таки per-site, попробуй покластеризовать по
HASH(siteid) с каким-нибудь невменяемым количеством кусков типа 1000.

Это хорошо бы, да. Но тут есть одна загвоздка, которая состоит именно в "суточной" природе таблицы: записи должны храниться строго за сутки - следить за этим можно только с помощью значения колонки DATE, удаляя записи с WHERE по этой колонке (тут даже не важно, по какой конкретно - главное, что не по siteid). Операции пересчета (когда из необработанной статистики делается суммарная) также делаются за определенные временные интервалы и потому опять же пользуются колонкой DATE (поэтому, кстати, тысячи сайтов в одной таблице и хранятся - все равно везде лазить по DATE; а еще иметь постоянно разрастающееся количество таблиц как-то неуютно немного)

Я так понимаю, partitioning хорош в тех случаях, когда поиск по таблице базируется на значении какой-то одной колонки - по ней и разбивается таблица.
Если же используются несколько ключей, то это может и замедлить работу, поскольку приходится искать в каждом partition'е отдельно.

Так что я даже и не знаю, что тут придумать.. :о
Прямо хоть делай две таблицы - одну по DATE разбивай, вторую - по siteid...

Тут же сразу вопрос: DATE у меня будет постоянно плыть, медленно увеличиваясь. Соответственно, рано или поздно (скорее, рано) структура разделов будет становиться морально устаревшей, придется периодически делать ALTER TABLE.
Так вот, вопрос: ALTER TABLE на partitioned-таблице делается по той же процедуре, что и на обычной? Меня это интересует потому, что если делается ПОЛНАЯ копия таблицы, то это значит полчаса (а то и больше) простоя на каждую такую операцию. Чтобы иметь значительный выигрыш в скорости поиска по разбивающему ключу, надо разбить хотя бы на несколько десятков разделов. Поскольку все разделы живут сутки, получается, что набор разделов надо будет обновлять раз в час, ну в два. Понятно, что полчаса простоя на два часа работы - это не очень smile.

Неактивен

 

#9 13.08.2009 23:15:46

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: долгий выбор данных

Кстати. Мне тут пришла мысль: всё, что мы тут обсуждали - это, конечно, хорошо, полезно и интересно smile
Но че-то мы отошли от проблемы. Мне ведь нужно вытащить строковую колонку, которая не в ключе. По-моему, partitioning мне бы тут не помог, т.к. у меня медленная стадия - не поиск по ключу, а выбор данных с диска, который будет так же медленной происходить, как и для обычной таблицы.
(или нет?)

Неактивен

 

#10 14.08.2009 13:49:43

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6756

Re: долгий выбор данных

У тебя медленная стадия — беганье за тысячей данных рандомно по таблице.
Если эта тысяча данных лежит в последовательных страницах, получается
последовательное чтение, что в разы быстрее. Медленно не чтение, медленны
сики по диску. Разбиение таблицы на тысячу маленьких сделает так, что в
одной «физической» табличке будут лежать единицы сайтов, тем самым
обеспечивая последовательное чтение.

Вчера вечером также подумал, что, возможно, замета PK с id на (site_id, uuid)
(+ выкинуть id + выкинуть ключ по uuid + переписать запросы так, чтобы везде
работал site_id) значительно улучшит работу таблицы. Не смотря на увеличение
размера PK.

Неактивен

 

#11 16.08.2009 23:25:29

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: долгий выбор данных

Вчера вечером также подумал, что, возможно, замета PK с id на (site_id, uuid)
(+ выкинуть id + выкинуть ключ по uuid + переписать запросы так, чтобы везде
работал site_id) значительно улучшит работу таблицы. Не смотря на увеличение
размера PK.

Да, это идея хорошая. Учитывая, что я еще и uuid сделал BINARY(4) вместо CHAR(36) (60 символов, латинские буквы и цифры, могут дать 12 млн. комбинаций; учитвая, что сессия живет сутки и проверяется отдельно для каждого siteid, вероятность пересечения ключа получается все равно оч. малая), а PK у меня был не 4 байта, а 8, то ваще намного лучше станет.
Только вот InnoDB все равно неявный PK создает ведь.. Имеет ли смысл удалять при этом явный, если он все равно создастся?

Неактивен

 

#12 17.08.2009 01:25:03

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6756

Re: долгий выбор данных

Нет, лучше всегда иметь явный, и лучше всегда извлекать из кластеризации
максимальную выгоду. Я предложил как раз пойти вразрез с принципом «в
InnoDB должен быть короткий PK» и сделать более длинный PK, но более правильный.
Ну и параллельно избавиться от ненужных вторичных индексов, чтобы табличка
не начала тормозить (таки принцип то нарушили).

Неактивен

 

#13 17.08.2009 01:41:20

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: долгий выбор данных

Че-то я затупил... PK - это ж необязательно autoincrement
Теперь все понятно smile

Неактивен

 

#14 20.08.2009 14:47:17

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: долгий выбор данных

У меня появилась идея, как обуздать-таки эту таблицу.

Основная проблема у меня заключалась в том, что используются два основных ключа - (siteid, sessionkey) - для уникальности сессии и DATE - для всего остального (т.к. все другие операции основаны на дате записи).
В общем, идея такая: вместо одной таблицы сделать две, одну - для сессий:

CREATE TABLE sessionkeys (
siteid INT NOT NULL,
sessionkey BINARY(4) NOT NULL,
DATE TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (siteid, sessionkey),
KEY (DATE)
);

(Мне тут дата все-таки нужна, т.к. сессии не бесконечные должны быть, и удалять по дате тоже, поэтому и ключ нужен)

а вторую - для всего остального (точнее, там все остальное - это источник, откуда посетитель пришел и вообще данные об этом); вот её-то как раз и разбить по UNIXTIME()

CREATE TABLE sessiondata (
UNIXTIME INT NOT NULL,
siteid INT NOT NULL,
/* ... тут строковые столбцы без ключей ... */,
)
PARTITION BY RANGE (UNIXTIME) (
    PARTITION p0 VALUES LESS THAN (N),
    PARTITION p1 VALUES LESS THAN (N + 60),
     PARTITION p1 VALUES LESS THAN (N + 120),
     ...
     /* и так разел на каждую минуту; итого за сутки 24 х 60 = 1440 разделов */
     ...
    PARTITION p1439 VALUES LESS THAN (N + 86340)
);


где N - время примерно около операции создания всей этой штуки.

Основной вопрос в том, превысит ли выигрыш от быстрого удаления и выборки информации в таблице sessiondata потери в удалении по дате в sessionkeys, а также в постоянных инсертах в две таблицы вместо одной (хотя и близкие к ней по размеру и составу ключей).

Неактивен

 

#15 20.08.2009 15:55:47

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6756

Re: долгий выбор данных

Честно говоря, не понял, чего ты собираешься добиться, но второй таблице явно не
хватает ключевых полей — sessionkey там должен быть

Неактивен

 

#16 20.08.2009 17:33:00

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: долгий выбор данных

Я собираюсь разбить одну таблицу (ту, которая описана в головном сообщении) на две (см. моё предыдущее сообщение), запись будет идти одновременно в обе этих таблицы. При этом уникальность ключа сессии будет проверяться по таблице sessionkeys. Во-второй таблице столбец sessionkey вообще не нужен, т.к. вставка туда будет проходить только после проверки пары (siteid, sessionkey) по первой.

Неактивен

 

#17 20.08.2009 18:00:46

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6756

Re: долгий выбор данных

Я сдуру решил, что эти данные во второй таблице для чего-то нужны (судя по названию —
там хранятся данные сессии). Если их вытаскивать из таблицы не нужно (основываясь на
uid сессии), то никаких проблем, конечно, нету smile

В любом случае, тут будет какая-то доля эксперимента — будет ли так быстрее, или нет.

Неактивен

 

#18 20.08.2009 22:52:01

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: долгий выбор данных

Еще парочка вопросов:

1. По минутам фиг у меня получится разбить, т.к. разрешается не больше 1024 разделов на таблицу, включая subpartition'ы.
Чем, помимо этого, ограничивается сверху число разделов?
Как я понимаю, для операций по ключу чем больше разделов - тем лучше. Почему бы всегда не делать 1024 раздела в таком случае (если нет операций по другим ключам)?

1a. Он нормально отнесется к RANGE-разбиению по UNIX_TIMESTAMP(DATE) ?

2. Как у разделов обстоят дела в JOIN'ами по разбивающему ключу? Все нормально, нет никаких подводных камней?

Неактивен

 

#19 21.08.2009 13:17:04

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6756

Re: долгий выбор данных

Да, очень неприятное ограничение. Но — можно пересобрать сервер с новым значением wink
Предлагаю 1а и 2 проверить самостоятельно. Я никаких проблем не вижу smile

Неактивен

 

#20 21.08.2009 17:24:59

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: долгий выбор данных

Т.е., грубо говоря, разделов много не бывает?
Они какие-нибудь ресурсы потребляют вообще? Какие нибудь там файловые дескрипторы и т.п., когда смотришь, и бац - у тебя что-то закончилось, и потом оказывается, что это из-за partitioning'а.
(это я все никак не могу понять, стоит ли мне делать макс. количество разделов или это где-то аукнется)

Неактивен

 

#21 21.08.2009 17:53:55

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6756

Re: долгий выбор данных

Если вопрос разряда «стоит ли перекомпилировать» — нет, не стоит. Попробуй сначала на 1024.
Если будет прирост производительности, но недостаточный — тогда уже пересобирать.

Неактивен

 

#22 21.08.2009 18:09:09

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: долгий выбор данных

Понятно smile
(я вообще не имел в виду перекомпиляцию; я в том смысле спрашивал, что не приводит ли увеличение количества разделов к потере производительности за счет траты ресурсов на обслуживание каждого раздела)

Неактивен

 

#23 21.08.2009 18:21:51

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6756

Re: долгий выбор данных

Ресурс на обслуживание == лишние открытые таблицы (i.e. файлхэндлы). Не так много, чтобы было плохо :-)

Неактивен

 

#24 21.08.2009 18:30:23

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: долгий выбор данных

А они все время висят открытые (все 1024 штуки) или висит один общий на таблицу, а на конкретные разделы открываются только когда их трогают?

Неактивен

 

#25 21.08.2009 19:30:59

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6756

Re: долгий выбор данных

Открываются все сразу, и закрываются все сразу.

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson