Обновление MYSQL для 40-миллионной таблицы записей с выделенным ОЗУ емкостью 128 ГБ занимает много времени - PullRequest
0 голосов
/ 12 февраля 2019

У нас проблемы с обновлениями на одной таблице, занимающие много времени.Таблица содержит ~ 30 миллионов строк.

Задание запускается каждый день, который усекает таблицу и вставляет новые данные из других источников в эту таблицу.

Вот таблица:

CREATE TABLE tempportfolio1 (
  SR_NO int(4) NOT NULL AUTO_INCREMENT,
  TR_DATE date DEFAULT NULL,
  TRAN_CODE decimal(18,0) DEFAULT NULL,
  TRAN_TYPE varchar(20) DEFAULT NULL,
  SCH_CODE bigint(8) DEFAULT NULL,
  Nature varchar(25) DEFAULT NULL,
  UNITS decimal(19,4) DEFAULT NULL,
  BAL_UNITS decimal(19,4) DEFAULT NULL,
  DIVD_RECD double DEFAULT '0',
  FOLIO_NO varchar(50) DEFAULT NULL,
  FLAG varchar(5) DEFAULT NULL,
  MBALANCE double DEFAULT NULL,
  PBALANCE double DEFAULT NULL,
  MTotalBalance double DEFAULT NULL,
  PL_NOTIONAL decimal(19,4) DEFAULT NULL,
  PL_BOOKED decimal(19,4) DEFAULT NULL,
  AGE int(4) DEFAULT NULL,
  RET_ABS decimal(19,4) DEFAULT NULL,
  RET_CAGR decimal(19,4) DEFAULT NULL,
  INDEX_AMT decimal(19,4) DEFAULT NULL,
  RET_INDEX_ABS decimal(19,4) DEFAULT NULL,
  Ret_Index_CAGR decimal(19,4) DEFAULT NULL,
  CURRENT_AMT decimal(19,4) DEFAULT NULL,
  GAIN_LOSS_LT decimal(19,4) DEFAULT NULL,
  GAIN_LOSS_ST decimal(19,4) DEFAULT NULL,
  UNITS_FOR_DIVID decimal(19,4) DEFAULT NULL,
  factor double DEFAULT NULL,
  LatestNav double DEFAULT '10',
  NavDate date DEFAULT NULL,
  IType int(4) DEFAULT NULL,
  Rate double DEFAULT NULL,
  CurrAmt double DEFAULT NULL,
  IndexVal double DEFAULT NULL,
  LatestIndexVal double DEFAULT NULL,
  Field int(4) DEFAULT NULL,
  Client_Code int(4) DEFAULT NULL,
  Branch_Code int(4) DEFAULT NULL,
  Rm_Code int(4) DEFAULT NULL,
  Group_Name varchar(100) DEFAULT NULL,
  Type1 varchar(20) DEFAULT NULL,
  Type2 varchar(20) DEFAULT NULL,
  IsOnline tinyint(3) unsigned DEFAULT NULL,
  SFactor double DEFAULT NULL,
  OSch_Code int(4) DEFAULT NULL,
  PRIMARY KEY (SR_NO),
  KEY SCH_Code (SCH_CODE),
  KEY OSch_Code (OSch_Code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

примечание: причина наличия этих индексов в том, что у нас есть много вариантов выбора и обновлений в SP, которые уменьшат сканирование таблицы.

   UPDATE TempPortFolio1
          INNER JOIN Clients
             ON Clients.ClientId = TempPortFolio1.Client_Code
   SET IType = InvCode;


      UPDATE TempPortFolio1
             INNER JOIN SchDate ON TempPortFolio1.Sch_Code = SchDate.Sch_Code
      SET LatestNav = NavRs, NavDate = LDate;


    UPDATE TempPortFolio1
    SET RATE = 0
    WHERE TRAN_TYPE = 'BONUS';


    UPDATE TempPortFolio1
    SET LatestNav = 10
    WHERE LatestNav = 0 OR LatestNav IS NULL;


    UPDATE TempPortFolio1
    SET NavDate = Tr_date
    WHERE NavDate < Tr_date AND Tran_Type <> 'Reinvestment';


    UPDATE TempPortFolio1
    SET Age = DATEDIFF(NAVDATE, TR_DATE),
        CurrAmt = (LatestNav * Units),
        PL_Notional = (UNITS * (LatestNav - Rate)),
        Divd_Recd = 0;




    UPDATE TempPortFolio1 TP INNER JOIN snature_new SM ON SM.CLASSCODE = TP.Type2
    SET GAIN_LOSS_ST = (CASE WHEN (Age < 365) THEN PL_Notional ELSE NULL END),
        GAIN_LOSS_LT = (CASE WHEN (Age >= 365) THEN PL_Notional ELSE NULL END)
    WHERE SM.Indexation = 0;


    UPDATE TempPortFolio1 TP INNER JOIN snature_new SM ON SM.CLASSCODE = TP.Type2
    SET GAIN_LOSS_ST =
           (CASE
               WHEN (TIMESTAMPDIFF(MONTH, TR_DATE, NAVDATE) < 36)
               THEN
                  PL_Notional
               ELSE
                  NULL
            END),
        GAIN_LOSS_LT =
           (CASE
               WHEN (TIMESTAMPDIFF(MONTH, TR_DATE, NAVDATE) >= 36)
               THEN
                  PL_Notional
               ELSE
                  NULL
            END)
    WHERE SM.Indexation = 1;


     UPDATE TempPortFolio1
   SET RET_INDEX_ABS = ((LatestIndexVal - IndexVal) / IndexVal) * 100;


   UPDATE TempPortFolio1
   SET Ret_Index_CAGR =
          CASE
             WHEN Age <= 365
             THEN
                ((CONVERT(RET_INDEX_ABS, decimal) / age) * 365)
             ELSE
                  (  POWER((((LatestIndexVal)) / (IndexVal)),
                           (365 / CONVERT(IFNULL(AGE, 1), decimal)))
                   - 1)
                * 100
          END
   WHERE     age <> 0
         AND LatestIndexVal <> 0
         AND IndexVal <> 0
         AND AGE IS NOT NULL;


   UPDATE TempPortFolio1
   SET ret_abs =
            (  ((((UNITS * LATESTNAV) + DIVD_RECD)) - (UNITS * RATE))
             / (UNITS * RATE))
          * 100
   WHERE UNITS <> 0 AND rate <> 0;

   UPDATE TempPortFolio1
   SET RET_CAGR =
          CASE
             WHEN Age <= 365
             THEN
                ((ret_abs / age) * 365)
             ELSE
                  (  POWER(
                        ((((UNITS * LATESTNAV) + DIVD_RECD)) / (UNITS * RATE)),
                        (365 / CONVERT(IFNULL(AGE, 1), DECIMAL)))
                   - 1)
                * 100
          END
   WHERE age <> 0 AND UNITS <> 0 AND rate <> 0 AND AGE IS NOT NULL;



   UPDATE TempPortFolio1
   SET Age = 0, LatestNav = 10
   WHERE Age IS NULL;

   UPDATE TempPortFolio1
   SET Factor = (UNITS * RATE * AGE);

   UPDATE TempPortFolio1
   SET SFactor = (UNITS * RATE * IndexVal * AGE);

есть многоОбновление между тем, но это занимает меньше времени. У причины только два индекса, потому что все вышеперечисленные запросы обновляют всю таблицу (40 миллионов записей).поэтому я думаю, что для этого не нужен индекс.

Каждое обновление занимает почти 25 минут. На сервере достаточно Ram для всех операций.Я пробовал временную таблицу, но без улучшения производительности, так как вся таблица обновлена, логика разделов не поможет, я так думаю .?

Я выполняю этот запрос на Windows 10. Есть ли способ увеличить скоростьзапрос ОБНОВЛЕНИЯ?какие-либо изменения, связанные с настройкой, были бы полезны?

, пожалуйста, помогите

- изменить

здесь приведено объяснение для более чем одного запроса таблицы присоединения, здесь приведено объяснение плана обновления 2

1   SIMPLE  SchDate     index   PRIMARY,Sch_Code,IDX_1  Sch_Code    4       39064   100 Using index
1   SIMPLE  TempPortFolio1 ref SCH_Code    SCH_Code    9   SchDate.Sch_Code    1   100 Using index condition.

для других обновлений просто с одной таблицей, поэтому я думаю, что объяснение не требуется.

Ответы [ 3 ]

0 голосов
/ 14 февраля 2019

Пройдите по столу, используя PRIMARY KEY.Проверьте 1000 строк одновременно.Подробности обсуждаются здесь

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

Не используйте OFFSET и LIMIT- это становится все медленнее и медленнее.

Некоторые из ваших UPDATEs могут быть в порядке с индексом:

UPDATE TempPortFolio1
SET RATE = 0
WHERE TRAN_TYPE = 'BONUS';

может использовать INDEX(TRAN_TYPE).

Но те, у кого нет условия WHERE, должны будут проверить все строки 40M.Даже если таблица может помещаться в buffer_pool, это все равно займет много времени.

Таблица, возможно, толще, чем должна быть.

  • decimal(19,4) занимает 9 байтов и допускает значения до 999999999999999,9999;действительно ли у вас такие большие значения?
  • AGE int(4) - если вы не говорите о «возрасте» в секундах людей, я предлагаю вам использовать 1-байт TINYINT UNSIGNED вместо 4-байт INT SIGNED.(Между тем, (4) ничего не значит.) О, я вижу, что AGE может быть в «днях», поэтому, возможно, 2-байтовый SMALLINT UNSIGNED (диапазон 0,64 КБ) может быть подходящим.
  • DOUBLE занимает 8 байтов и подвергается риску дополнительного округления из-за переключения между двоичным и десятичным.

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

Вернемся к медленным UPDATE.Что беспокоит:

  • Просто, что запрос занимает много времени?(Крошка займет еще больше времени в истекшем времени.)
  • Что блокирует другие вещи?(Чанкинг избегает этого.)
  • Что вам нужны изменения сейчас ?(Слишком плохо.)
  • Что вам нужно, чтобы все соответствующие строки были изменены как одно и то же «мгновение», даже если этот момент произошел через несколько минут после запуска запроса?(Это то, что вы получаете с одиночным, медленным, UPDATE.)
0 голосов
/ 27 февраля 2019

этот ответ для тех, кто хочет знать.

Итак, поскольку данные усекаются / вставляются ежедневно и задания выполняются каждый день.

мы создали один SP, который отбрасывает и воссоздает таблицу с разделом динамического диапазонав соответствии с количеством строк (которые мы рассчитываем количество (*)).

мы сделали второй SP, который имеет все обновления (около 30), которые являются динамическими с разделом, который должен применяться при выполнении

than we Created script file which execute every day and do following task
      1   call 1'st SP
      2   create number of dynamic(replace event name and partition number ) event (after interval one minute) as number of partition  using file .
      3  each event will call Second SP with different Partition Paralleled .

Этот процесс повторяется каждый день, и это заняло всего 30 минут) с 40 миллионами строк для выполнения всего обновления.

0 голосов
/ 12 февраля 2019

Разделить ОБНОВЛЕНИЯ на куски, например, с помощью LIMIT 1000 (ограничение работает с запросами ОБНОВЛЕНИЯ).

Например:

 UPDATE TempPortFolio1
    SET Age = DATEDIFF(NAVDATE, TR_DATE),
        CurrAmt = (LatestNav * Units),
        PL_Notional = (UNITS * (LatestNav - Rate)),
        Divd_Recd = 0 LIMIT 1000;
...