Оптимизация MySQL GROUP BY / ORDER BY для расчета пересечения множества - PullRequest
1 голос
/ 12 января 2011

Этот сценарий несколько упрощен, чтобы прояснить проблему. Моя ситуация связана с набором записей данных в MySQL.

CREATE TABLE `records` (                                          
  `id` bigint(20) NOT NULL,                                                       
  `property1` bigint(20) NOT NULL,
  `property2` bigint(20) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `property1` (`property1`),
  KEY `property2` (`property2`)
);

Из каждой записи мы генерируем и храним переменное количество ключей (хэшей) на основе данных записи.

CREATE TABLE `rkeys` (
  `rKey` bigint(20) NOT NULL,
  `rId` bigint(20) NOT NULL,
  KEY `rKey` (`rKey`),
  KEY `rId` (`rId`),
  FOREIGN KEY (`rId`) REFERENCES `records` (`id`)
);

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

Может быть, например, 5 миллионов записей и 50 миллионов ключей.

То, что я пытаюсь сделать, - это нечеткий поиск по набору ключей - сопоставить запись с записями в базе данных с наибольшим количеством общих ключей. Результаты также необходимо отфильтровать по свойствам в таблице записей.

Запрос, с которым я работал, выглядит следующим образом:

SELECT rkeys.rId, records.property1, SUM(1) as score 
FROM rkeys, records
WHERE 
   (rKey = 10 OR rKey = 11 OR rKey = 13 OR rKey = 14) AND 
    rkeys.rId = records.id AND 
    records.property1 = 1 AND
    records.property2 = 2 
GROUP BY rId ORDER BY score DESC;

Производительность в порядке, если число записей с любым заданным ключом довольно мало; проблема в том, что я нажимаю клавишу, которая появляется в нескольких тысячах записей (скажем, 5000). Внезапно производительность GROUP BY / ORDER BY падает с обрыва (15-20 с на запрос). Обратите внимание, что сглаживание распределения ключей на самом деле не вариант - сами данные записи распределены неравномерно.

Кажется, что проблема объединения с записями не является ядром проблемы - я просто включаю ее для контекста. Я все еще вижу ту же проблему, если все, что я хочу сделать, это:

SELECT rId, SUM(1) as score 
FROM rkeys
WHERE rKey = 10 OR rKey = 11 OR rKey = 13 OR rKey = 14
GROUP BY rId ORDER BY score DESC;

Объяснить вывод:

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: rkeys
         type: index
possible_keys: rKey
          key: rKey
      key_len: 8
          ref: NULL
         rows: 1
        Extra: Using where; Using temporary; Using filesort

Есть ли способ, которым я могу реструктурировать эту таблицу или запрос, чтобы ускорить эту операцию?

Ответы [ 4 ]

0 голосов
/ 07 мая 2017

«Ключевыми значениями являются хэши, чтобы распределить их по пространству клавиш более равномерно» - это на самом деле плохая идея для производительности.Как только данные становятся слишком большими для кэширования, вы будете замедлены случайностью.

Таблица Keys пахнет очень похоже на таблицу сопоставления многие: многие. Здесь - несколько советов по улучшению производительности такой таблицы.И это может ускорить ваш SELECT.

Ваш SELECT должен значительно улучшиться с этим «составным» и «охватывающим» индексом:

INDEX(property1, property2, id)

( Дополнительные советы при создании оптимальных индексов.)

0 голосов
/ 12 января 2011

Я новичок, но попробуйте составной индекс на (rKey, rId) или (rId, rKey)

0 голосов
/ 13 января 2011

попробуйте что-то вроде этого

SELECT rId, Count(*) as score 
FROM rkeys
WHERE rKey = 10 OR rKey = 11 OR rKey = 13 OR rKey = 14
GROUP BY rId ORDER BY score DESC

и добавьте индекс в таблицу

(rKey,rId)

Хотя замена Sum на count не должна иметь большого значения.(в любом случае в MSSQL)

0 голосов
/ 12 января 2011

Вы пытались добавить некластеризованные индексы (индексы) в эти поля? В прошлом я не видел, чтобы ключи делали это автоматически, кроме неявного создания кластеризованного индекса, которое объявление первичного ключа выполняет в некоторых механизмах SQL.

...