Как мне увеличить скорость большого количества обновлений в MySQL против SQL Server? - PullRequest
0 голосов
/ 17 мая 2018

У меня есть приложение, которое я пишу на Java с простым SQL, поэтому здесь нет пользовательских MySQL или SQL Server - оно может работать на любом из них.Одна операция сохранения данных должна извлечь данные из БД, сравнить их с тем, что было отправлено, а затем вставить, обновить или удалить соответствующим образом.

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

Итак, мои ВСТАВКИ - я просто вызываю метод Statement.addBatch() для всего набора данных, который нужно вставить, и драйвер JDBC создает

INSERT INTO data (parentId, seriesDate, valueDate, value) 
    VALUES (a,b,c,d),(a,b,e,f),(a,b,g,h)... etc

DELETEs - Я просто удаляю весь лот с помощью

DELETE FROM data WHERE parentId = a AND seriesDate = b;

, и я могу вставить их заново.(Может быть, лучше выбрать другой подход, составив большую длинную

DELETE FROM data WHERE (parentId = 1 AND seriesDate = b) 
    OR (parentId = 2 AND seriesDate = c) 
    OR (parentId = 3 AND seriesDate = d)  ...

, но здесь проблема не в этом, моя главная проблема в том, что ОБНОВЛЕНИЯ действительно медленные - в два раза медленнеекак INSERT

я получаю 1000 отдельных операторов:

UPDATE data SET value = 4 
    WHERE parentId = 1 AND seriesDate = '' AND valueDate = '';

В SQL Server ОБНОВЛЕНИЯ так же быстро, как и INSERT , но в MySQL я вижу, что он работает в 10 раз медленнее.

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

[ОБНОВЛЕНИЕ 2018-05-17] Вот запрошенный DDL - и, к сожалению, я не могу изменить это (пока) поэтому любые предложения, связанные с изменениями схемы, не помогут, по крайней мере, в этом году: (

CREATE TABLE data (
  parentId INT UNSIGNED NOT NULL,
  seriesDate DATE NOT NULL,
  valueDate DATE NOT NULL,
  value FLOAT NOT NULL,
  versionstamp INT UNSIGNED NOT NULL DEFAULT 1,
  createdDate DATETIME DEFAULT CURRENT_TIMESTAMP,
  last_modified DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  CONSTRAINT pk_data PRIMARY KEY (parentId, seriesDate, valueDate),
  CONSTRAINT fk_data_forecastid FOREIGN KEY (parentId)
    REFERENCES forecast (id)
) MAX_ROWS 222111000;

CREATE TRIGGER trg_data_update BEFORE UPDATE ON data
  FOR EACH ROW SET NEW.versionstamp = OLD.versionstamp + 1;

CREATE INDEX ix_data_seriesdate ON `data` (seriesDate);

INSERT :

INSERT INTO `data` (`parentId`, `valueDate`, `value`, `seriesDate`)
    VALUES (52031,'2010-04-20',1.12344,'2013-01-10')

EXPLAIN PLAN:
id: 1
select_type: INSERT
table: data
partitions:
type: ALL
possible_keys: PRIMARY,ix_data_seriesdate

и ОБНОВЛЕНИЕ :

UPDATE `data` SET `value` = -2367.0
    WHERE `parentId` = 52005 AND `seriesDate` = '2018-04-20' AND `valueDate` = '2000-02-11'

EXPLAIN PLAN:
id: 1
select_type: UPDATE
table: data
partitions: 
type: range
possible_keys: PRIMARY,ix_data_seriesdate
key: PRIMARY
key_len: 10
ref: const,const,const
rows: 1
filtered: 100
Extra: Using where

и УДАЛЕНИЕ :

DELETE FROM `data` WHERE `parentId` = 52030 AND `seriesDate` = '2018-04-20'

EXPLAIN PLAN:
id: 1
select_type: DELETE
table: data
partitions: 
type: range
possible_keys: PRIMARY,ix_data_seriesdate
key: PRIMARY
key_len: 7
ref: const,const
rows: 1
filtered: 100
Extra: Using where

FYI 2поля обновляются автоматически - last_modified с помощью предложения ON UPDATE и versionstamp с помощью триггера (и опять же, я не могу отказаться от этой функции).

1 Ответ

0 голосов
/ 17 мая 2018

Пути, которые я нашел для улучшения операторов UPDATE:

  • использовать вспомогательные таблицы (которые могут "пакетировать" ваши обновления)
  • проверка на ненужные триггеры
  • улучшить индексацию (для предложения WHERE)
  • Временные таблицы промежуточного уровня OLAP или OLTP (они допускают пакет обновлений)

Е.Г.

CREATE TABLE #TempData ( 
  parentId INT UNSIGNED NOT NULL,
  seriesDate DATE NOT NULL,
  valueDate DATE NOT NULL,
  value FLOAT NOT NULL
);

INSERT INTO #TempData ( parentId, seriesDate, valueDate, value ) VALUES ( .... ), ( .... ), ( .... );

UPDATE
  data
SET
  value = #TempData.value
FROM
  #TempData
WHERE
  data.parentId = #TempData.parentId AND
  data.seriesDate = #TempData.seriesDate AND
  data.valueDate = #TempData.valueDate;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...