Как настроить таблицы ключей с 15M + строк для высокой производительности и низкой стоимости?

0

Мне нужно обеспечить максимальную производительность для таблицы с 15M+ строками в базе данных MySQL, размещенной в AWS, с использованием Aurora (экземпляр малого размера в настоящее время). Эта таблица, по существу, предназначена для отслеживания временной привязки владения и обновления единиц продукта с течением времени, а также для каждой единицы другой базовой информации, такой как серийный номер.

Столбцы:

UnitId, ScanTime, Model, SerialNumber, MfrTimestamp, UpdateTimestamp, CustomerId

Заявление о создании таблицы

CREATE TABLE 'UnitHistory' (
  'UnitId' bigint(20) NOT NULL,
  'ScanTime' int(11) NOT NULL,
  'Model' bigint(20) NOT NULL,
  'SerialNumber' int(11) NOT NULL,
  'MfrTimestamp' int(11) NOT NULL,
  'UpdateTimestamp' int(11) DEFAULT NULL,
  'CustomerId' bigint(20) DEFAULT NULL,
  PRIMARY KEY ('UnitId','ScanTime')
);

Строки будут добавлены с течением времени, но НИКОГДА не будут изменены.

Я выбрал UnitId и ScanTime в качестве основного ключа, потому что эти два вместе являются достаточными, чтобы всегда быть уникальными.

Запрос 1

Запрос, который я наиболее часто использую, в идеале даст список всех UnitId для конкретной модели, а также самую последнюю информацию об устройстве. Следующий запрос будет работать, но, конечно же, также будет возвращать больше строк, чем мне нужно (избыточные данные):

SELECT UnitId, SerialNumber, MfrTimestamp, UpdateTimestamp, CustomerId FROM UnitHistory WHERE Model=2500;

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

Запрос 2

В другом очень часто используемом запросе будет создан базовый набор деталей и истории для любой конкретной единицы, например:

SELECT ScanTime, SerialNumber, MfrTimestamp, UpdateTimestamp, CustomerId FROM UnitHistory WHERE UnitId=1234567;

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

Резюме

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

Один из факторов стоимости заключается в том, что я полагаю, что мой рабочий набор должен вписываться в ОЗУ, чтобы избежать множества ИО с момента обвинений AWS для МО. Мой текущий экземпляр базы данных имеет 2 ГБ ОЗУ, и по соображениям затрат я не хочу его обновлять.

  • 0
    Вы не сможете добиться максимальной производительности, не потратив немного $$. Можете ли вы опубликовать результаты выполнения для запроса 1 и 2?
  • 0
    @krishKM Я, наверное, должен был заявить, что «максимальная производительность при использовании 2 ГБ ОЗУ». На самом деле я еще не заполнял таблицу данными и не выполнял запросы к ней, потому что программное обеспечение, которое ее заполняет, еще не готово. Я просто пытаюсь подготовить таблицу и функционировать как можно лучше, когда данные будут наконец заполнены.
Показать ещё 1 комментарий
Теги:
amazon-web-services
rds

2 ответа

2
Лучший ответ

Для вашего запроса 1 вы должны иметь этот индекс:

ALTER TABLE UnitHistory ADD INDEX (Model, ScanTime);

Чтобы получить последние:

SELECT UnitId, SerialNumber, MfrTimestamp, UpdateTimestamp, CustomerId 
FROM UnitHistory WHERE Model=2500
ORDER BY ScanTime DESC LIMIT 1;

Здесь демонстрационный пример использования EXPLAIN для подтверждения запроса использует индекс (который называется "Модель" после первого столбца индекса, так как я не дал ему имя в своем тесте):

mysql> explain SELECT UnitId, SerialNumber, MfrTimestamp, UpdateTimestamp, CustomerId FROM UnitHistory WHERE Model=2500 order by scantime desc limit 1;
+----+-------------+-------------+------------+------+---------------+-------+---------+-------+------+----------+-------------+
| id | select_type | table       | partitions | type | possible_keys | key   | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------------+------------+------+---------------+-------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | UnitHistory | NULL       | ref  | Model         | Model | 8       | const |    1 |   100.00 | Using where |
+----+-------------+-------------+------------+------+---------------+-------+---------+-------+------+----------+-------------+

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

mysql> explain SELECT ScanTime, SerialNumber, MfrTimestamp, UpdateTimestamp, CustomerId FROM UnitHistory WHERE UnitId=1234567;
+----+-------------+-------------+------------+------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table       | partitions | type | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------------+------------+------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | UnitHistory | NULL       | ref  | PRIMARY       | PRIMARY | 8       | const |    1 |   100.00 | NULL  |
+----+-------------+-------------+------------+------+---------------+---------+---------+-------+------+----------+-------+

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

0

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

Вот еще один способ для Query1. Создайте другую таблицу, такую как ваша UnitHistory. Create table UnitReadings like UnitHistory; but unitid being the primary key Create table UnitReadings like UnitHistory; but unitid being the primary key.

А затем UnitHistory таблицу UnitHistory и добавьте триггеры перед вставкой или после вставки. что-то вроде,

 Insert into 'UnitReading'(
    UnitId,
    ScanTime,
    Model,
    SerialNumber,
    MfrTimestamp,
    UpdateTimestamp,
    CustomerId
  ) values
  (
      NEW.UnitId,
      NEW.ScanTime,
      NEW.Model,
      NEW.SerialNumber,
      NEW.MfrTimestamp,
      NEW.UpdateTimestamp,
      NEW.CustomerId
  ) ON DUPLICATE KEY UPDATE
      ScanTime          = values(ScanTime),
      Model             = values(Model), 
      SerialNumber      = values(SerialNumber),
      MfrTimestamp      = values(MfrTimestamp),
      UpdateTimestamp   = values(UpdateTimestamp),
      CustomerId        = values(CustomerId);

Цель состоит в том, чтобы сохранить последнее чтение в "таблице заголовков", которая может содержать меньше строк, чем вся ваша история ваших строк (чтения * в день * дней). Через несколько лет вы можете превысить 15 м строк, но таблица заголовков может по-прежнему составлять около 1000 единиц или любое количество единиц, которые вы читаете. Вы можете значительно превысить ожидаемую производительность, используя эту таблицу заголовков "с вашей RAM 2 ГБ" :) :)

Не уверен, что вы можете реализовать это, но вы правильно поняли идею?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню