Оптимизация производительности БД с несколькими индексами для одной таблицы - PullRequest
0 голосов
/ 24 января 2019

У меня есть данные временных рядов о количестве предметов, которые я храню (в этом примере с игрушкой) в простой паре таблиц.На данный момент это делается в MySQL, но если существуют достаточно веские причины для решения моей проблемы в другой СУБД, я был бы всем вниманием!

Таблица ITEM имеет первичный ключ иодин текстоподобный столбец, который можно представить как описание, назовем его descr.Таблица DATAPOINT имеет первичный ключ и 3 других столбца: внешний ключ в таблицу ITEM (назовите его fk_item), дату и время, которое я назову timestamp, и значение с плавающей запятой, которое мы назовем value.Кроме того, существует совместное ограничение уникальности для пары столбцов (fk_item, timestamp) (нам нужно только одно значение в БД для данного элемента в данный момент времени).

Чтобы поставить на него действительные числа, DATAPOINT таблица содержит около 1 миллиарда строк, что является результатом наличия приблизительно 100 тысяч строк для каждого из 10 тысяч различных элементов.

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

Типичное чтение из этой БД будет включать небольшое количество элементов (полдюжины?), для которых мы хотим получить все значения в заданном диапазоне времени / даты (содержащие примерно 1 тыс. точек навещь).Для этого было бы очень удобно иметь индекс, равный (fk_item, timestamp), и применять совместные критерии уникальности для этого индекса.Эта мотивация для чтения такого типа: «Я хочу сделать линейный график из 2 или 3 элементов для этого 3-летнего диапазона».

Однако типичная запись для этой базы данных будет выглядеть совсем иначе.Это будет вставка одной точки данных для каждого из нескольких тысяч элементов с одинаковыми (или небольшим числом) временными метками.Эта мотивация для такой записи может быть интуитивно понятна как: «Я хочу добавить вчерашнюю точку данных для каждого отдельного элемента».Поэтому для записей такого рода было бы более практично иметь индекс, равный (timestamp, fk_item), и применять ограничение уникальности для этого индекса.

Важно, что для масштаба моих данных и оборудования нииз этих индексов могут быть полностью помещены в ОЗУ.

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

Итак, насколько я понимаю, если я строю таблицу с индексом (fk_item, timestamp), оптимизированным для чтения (и поместите ограничение уникальности там), тогда мои типичные чтения будут хорошими и быстрыми.Но я обеспокоен тем, что мои записи будут медленными, потому что нам нужно будет обновить индекс несмежным способом.Однако, если я построю таблицу с индексом (timestamp, fk_item), оптимизированным для записи (и наложу ограничение уникальности), то мои типичные операции записи будут быстрыми, но мои типичные операции чтения пострадают.

Есть ли способ получить лучшее из обоих миров?Например, если я построю два индекса: (fk_item, timestamp) и (timestamp, fk_item) и добавлю уникальность only к последнему из двух, будет ли это работать хорошо?Или же запись все равно будет продолжаться с «медленной» скоростью, потому что даже при наличии индекса, оптимизированного для записи (например, для проверки ограничения уникальности), индекс, оптимизированный для чтения, необходимо будет обновить при любых вставках, и это обновление будетбыть несмежным?

Заранее спасибо!

1 Ответ

0 голосов
/ 26 января 2019

Краткий ответ: (fk_item, timestamp) только.

Длинный ответ:

Что касается уникальности , то (fk_item, timestamp) и (timestamp, fk_item) одинаковы. Хотя они оба одинаково хорошо объявляют уникальность, они оба сосут у , являясь уникальным. Когда-нибудь определенный элемент появится дважды в одну и ту же секунду.

Вы упомянули "вчера". Итак, если запись действительно является промежуточной суммой за день , то (fk_item, date) является разумным.

При построении индекса всегда лучше иметь элемент даты / времени последний . Это так, что WHERE fk_item = 123 AND date BETWEEN ... AND ... может использовать этот индекс. Пишет, не важно (много), в каком порядке.

А как же PRIMARY KEY? Это так, но определение MySQL, UNIQUE и INDEX. Итак, если (fk_item, date) разумно, сделайте это PK. Это сделает запросы, которые должны смотреть на несколько строк для определенного элемента, более эффективными.

«Я хочу сделать линейный график из 2 или 3 элементов для этого 3-летнего диапазона». - Если это включает в себя миллионы строк, то вы разработали схему неэффективно. Вам необходимо создать и поддерживать сводную таблицу, скажем, ежедневных значений для каждого элемента. Тогда это будут сотни, а не миллионы строк - гораздо более жизнеспособные.

Вернуться к INSERTs. С 10k различных элементов и PRIMARY KEY(fk_item, date) в таблице, где происходит вставка, будет 10K пятен. Это на самом деле нормально, и будет примерно такой же скорости, как и некоторые другие заказы.

Ежедневные INSERTs лучше всего делать с LOAD DATA INFILE или с несколькими рядами INSERTs.

Я говорю с точки зрения MySQL. Часть, хотя, возможно, не все, что я говорю, относится к другим продуктам.

PARTITIONing - бесполезная идея для MySQL, если только вы не собираетесь очищать «старые» данные. (Я не могу говорить за Posgres.)

Если вы вставляете строки случайным образом , вы можете столкнуться с нереальными проблемами с производительностью. Это потому, что ваша реальная ситуация будет гораздо менее «случайной». Там будет только 10 тысяч мест, где вы делаете INSERTs сегодня, а не 1 миллиард. А завтра это будут «те же самые» 10 000 мест.

«как должна создаваться такая таблица» - Минимизируйте типы данных (например, не используйте 8-байтовый BIGINT для флага «да / нет»); Укажите оптимальный ПК (я предложил (item, day)). Но вы должны иметь предварительное значение SELECTs, чтобы рассчитать вторичные индексы. Нормализовать, где это необходимо (item_id), но не чрезмерно нормализовать (даты).

...