Медленный запрос при заказе по - PullRequest
0 голосов
/ 06 мая 2020

Для выполнения следующего запроса в таблице из 1.000.000 строк требуется более 20 секунд

SELECT max(listing.category) AS category,
    max(listing.subcategory) AS subcategory,
    max(listing.created_at) AS date,
    listing.keystring AS listing_keystring
FROM listing
WHERE listing.privacy > 10
GROUP BY listing.keystring
ORDER BY date
LIMIT 10

Если я удалю часть «порядок по», выполнение запроса займет менее 1 секунды.

Согласно оператору объяснения: EXTRA говорит: «Использование где; Использование временного; Использование файловой сортировки» Тип говорит: Индекс «Ключ говорит: list_idx_keystring_category»

Здесь оператор создания таблицы:

 'CREATE TABLE `listing` (`id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `bw` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `subcategory` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `category` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `place` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `time` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `is_hidden` tinyint(1) NOT NULL DEFAULT ''0'',
  `privacy` int(11) NOT NULL DEFAULT ''20'',
  `keystring` varchar(255) COLLATE utf8mb4_unicode_ci
      GENERATED ALWAYS AS (concat(`bw`,`category`,ifnull(`subcategory`,''''),ifnull(`place`,''''),ifnull(`time`,''''))) STORED,
  PRIMARY KEY (`id`),
  KEY `listing_idx_privacy` (`privacy`),
  KEY `listing_idx_keystring_category` (`keystring`,`category`),
  KEY `idx_listing_created_at_privacy` (`created_at`,`privacy`),
  KEY `idx_listing_created_at` (`created_at`),
  KEY `idx_listing_bw` (`bw`),
  KEY `idx_listing_subcategory` (`subcategory`),
  KEY `idx_listing_category` (`category`),
  KEY `idx_listing_place` (`place`),
  KEY `idx_listing_time` (`time`)
) ENGINE=InnoDB AUTO_INCREMENT=1500001
      DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci'

Есть ли что-нибудь, что можно сделать для повышения скорости?

Я пробовал добавлять разные комбинации индексов, но безуспешно ...

1 Ответ

1 голос
/ 06 мая 2020

Для этого запроса:

select 
    max(category) as category, 
    max(subcategory) as subcategory,
    max(created_at) as date, 
    keystring as listing_keystring
from listing
where privacy > 10
group by keystring
order by date
limit 10

Я бы начал со следующего индекса: (privacy, keystring). Это соответствует предикату where и столбцу group by. У вас нет этого индекса, поэтому сначала попробуйте.

Вы также можете попробовать: (privacy, keystring, category, subcategory, created_at); это довольно много столбцов, поэтому я не уверен, действительно ли MySQL учтет это, но попробовать стоит; в лучшем случае MySQL будет использовать это как индекс покрытия и выполнять весь запрос, глядя только на индекс.

Обратите внимание, что слепое создание индексов для многих столбцов комбинации не помогает. С одной стороны, стратегию индексирования необходимо настраивать для каждого запроса. С другой стороны, больше индексов означает больше места для хранения и больше работы для базы данных для каждой операции DML (update, insert, delete), что потенциально не дает преимуществ в запросах select. Если у вас нет веской причины сохранить все существующие индексы, я бы посоветовал их удалить.

...