Эффективный способ получения одного примера строки при использовании хэшей - PullRequest
0 голосов
/ 28 января 2019

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

CREATE TABLE featureMappings (
  id bigint(20) NOT NULL AUTO_INCREMENT,
  visitId bigint(20) NOT NULL,
  featureId bigint(20) NOT NULL,
  textValue text DEFAULT NULL,
  hashTextValue char(32) GENERATED ALWAYS AS (MD5(textValue)) VIRTUAL,
  PRIMARY KEY (id));
ALTER TABLE featureMappings
ADD INDEX fsHashTextValue (featureId, hashTextValue)

При обычном запуске эта таблица содержит приблизительно 40–100 миллионов строк.Существует много повторяющихся текстовых значений, поэтому я использую ключ hashTextValue, чтобы иметь возможность индексировать этот столбец.

Выполнение следующего запроса занимает около 25 секунд:

CREATE TEMPORARY TABLE temp AS
SELECT 
  featureId,
  hashTextValue
FROM 
  featureMappings
GROUP BY featureId, hashTextValue

Вопрос

Я хочу извлечь значение в textValue столбец рядом со столбцами featureId и hashTextValue.

Я пробовал два подхода.Оба этих фактора значительно увеличили время запроса, поэтому я ищу лучшее решение.

Замедленный вариант 1 - добавление textValue к запросу

При выполнении изменения belo на запрос время обработки составляло от 25 секунд до 10 минут.,Я пытался гуглить, как получается textValue, когда не используется агрегатная функция, но не смог найти четкого ответа.

CREATE TEMPORARY TABLE temp AS
SELECT 
  featureId,
  hashTextValue,
  textValue # I also tried MIN(textValue)
FROM 
  featureMappings
GROUP BY featureId, hashTextValue

Сложный вариант 2: итеративное обновление

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

SELECT featureId, hashTextValue INTO @fid, @htv 
FROM temp
WHERE textValue is NULL and hashTextValue IS NOT NULL
LIMIT 1;

SELECT textValue 
INTO @textValue
FROM featureMappings 
WHERE featureId = @fid and hashTextValue = @htv
LIMIT 1;

UPDATE temp
SET textValue = @textValue
WHERE featureId = @fid AND hashTextValue = @htv;

Конфигурация сервера

Это выполняется на AWS RDS Aurora на основе Mysql 5.7.Сервер имеет ограниченную (2 ГБ) память и обычно имеет меньше свободной памяти, чем размер индекса в таблице.

1 Ответ

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

План A: дедупликация при загрузке.Это тривиально, если сделать PK равным featureMappings быть PRIMARY KEY(featureId, hashTextValue) и использовать INSERT IGNORE при загрузке промежуточной таблицы.

План B: (Предполагается, что что-то мешает Плану А).indexes.

  PRIMARY KEY (featureId, hashTextValue, id),
  INDEX(id)

Это все еще имеет проблемы, но мне неясно, что должно произойти дальше.

Далее ...

SELECT featureId, hashTextValue INTO @fid, @htv 
    FROM temp
    WHERE textValue is NULL and hashTextValue IS NOT NULL
    LIMIT 1;

Проблема в том, что все медленнее и медленнее, когда вы едите через соответствующие предметы.Было бы лучше добавить явный PRIMARY KEY и пройти через temp.Фактически, это будет на порядок быстрее (если temp большое).Допустим, id это ПК;затем:

SELECT @id := id, @fid := featureId, @htv := hashTextValue INTO
    FROM temp
    WHERE textValue is NULL and hashTextValue IS NOT NULL
      AND id > @id   -- this picks up 'where you left off'
    LIMIT 1;

(инициализация с SET @id := 0;)

Теперь, когда у вас есть id, UPDATE становится проще и быстрее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...