Поиск активных записей — find_by_inventory_product_id периодически замедляется, несмотря на добавление индекса

У меня есть простая новая конечная точка API, которая включает в себя запрос моей недавно настроенной и заполненной таблицы — inventory_products.

Схема таблицы inventory_products:

CREATE TABLE `inventory_products` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `inventory_product_id` binary(16) DEFAULT NULL,
  `product_id` binary(16) DEFAULT NULL,
  `status` enum('ACTIVE','INACTIVE','DELETED') DEFAULT 'ACTIVE',
  `priority` int(11) DEFAULT '0',
  `inventory_service_id` tinyint(3) DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uc_inventory_product_id` (`inventory_product_id`),
  KEY `idx_product_status` (`product_id`,`status`)
) ENGINE=InnoDB AUTO_INCREMENT=76312817 DEFAULT CHARSET=utf8;

Конечная точка API в основном выполняет следующие действия:

def lookup_inventory_service_id
    return render_error_response(AUTH_ERROR, {status: 403}) unless client.name == PERMITTED_NAME

    ip_fetch_start = Time.now
    inventory_product = InventoryProducts.find_by_inventory_product_id(resource_attributes[:inventory_product_id])
    Rails.logger.info({inventory_product_id: resource_attributes[:inventory_product_id], inventory_product_fetch_time_ms: (Time.now - ip_fetch_start)*1000}.as_json)
    return head :not_found unless inventory_product
....

Проблема: Поиск inventory_product (find_by_inventory_product_id) — это стандартная функция, предоставляемая Rails ActiveRecord (я не перезаписывал ее в своей модели). Эта функция занимает от 10 мс до иногда даже 650 мс (нашел это из добавленных мной журналов). Почему в некоторых случаях это занимает так много времени, а в других — меньше, несмотря на то, что индекс Mysql существует для столбца, используемого при поиске?

Я упомянул inventory_product_id в качестве уникального ключа в своей схеме, и запрос MySQL, инициированный вышеуказанной функцией, использует inventory_product_id в качестве индекса из приведенного ниже оператора explain.

объяснить SELECT inventory_products.* FROM inventory_products WHERE inventory_products.inventory_product_id = 0x3a288cdce78d44618eadd72e240f26a4 LIMIT 1

id select_type тип таблицы visible_keys key key_len ref rows Extra 1 SIMPLE inventory_products const uc_inventory_product_id uc_inventory_product_id 17 const 1 NULL

Что-то не так в моей схеме? Нужно ли явно указывать inventory_product_id в качестве индекса mysql в схеме? Что-то вроде:

KEY `idx_product_status` (`product_id`,`status`)

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

Я использую Mysql 5.6 и рельсы - 3.2.8. Кроме того, мое приложение rails работает на сервере tomcat (версия — Apache Tomcat/7.0.16) внутри jruby (1.7.0)/


person user3903418    schedule 29.09.2019    source источник
comment
Попробуйте добавить inventory_product_id в качестве индекса и посмотрите, что получится.   -  person razvans    schedule 01.10.2019
comment
Если я не ошибаюсь, ограничение уникального ключа автоматически создает индекс, верно?   -  person user3903418    schedule 03.10.2019


Ответы (1)


Вот что должно происходить:

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

  1. Разверните BTree (3-4 уровня в глубину), чтобы найти индексную строку для [inventory_product_id, id]
  2. (при условии, что он нашел одну строку), используйте id для детализации данных BTree (вероятно, на 4 уровня в глубину).
  3. Извлеките все столбцы строки (так как вы сказали SELECT *).

Даже в очень холодной системе я бы не ожидал, что потребуется прочитать более 8 блоков. Если диски являются жесткими дисками, то я бы оценил максимум 80 мс для выполнения запроса. Между тем, я бы сказал, что 10-20 мс были бы типичными.

Итак... 630 мс означает, что происходит что-то еще. Особенно подозрительным будет любой запрос, касающийся этой таблицы.

Индекс (product_id, status) не имеет отношения к этому запросу.

UUID ужасно влияют на производительность, особенно когда индекс не помещается в ОЗУ. Сколько у вас доступно оперативной памяти? Каково значение innodb_buffer_pool_size?

person Rick James    schedule 10.10.2019