Search code examples
mysqlperformanceoptimizationquery-performanceinsert-update

MYSQL lot's of update on 40 million record table wih 128GB ram dedicated server take long time


We are having trouble with updates on a single table taking a long time. The table contains ~30 Million rows.

The job runs every day that truncates the table and inserts new data from other other sources in that table.

Here is the table:

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;

note: the reason for having this indexes is we have many selects and updates coming ahead in SP that will decrease the table scans.

   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);

there are lot's of update between those but that take less time . Reason only have two index because all above query update entire table (40 million record). so i think no index needed for that.

Each update take almost 25 minutes.server has enough Ram for all operation. I have tried temporary table, but no improvement on performance, as entire table updated no partition logic will help i think so.?

I am running this query on windows 10. Is there any way to increase the speed of the UPDATE query? any configure related changes would be helpful?

please help

-- edit

here is explain for more than one join table query here is explain plan of update 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.

for other updates are simple with one table,so i think no explain needed.


Solution

  • this answer for who want to know.

    So,as data truncate/insert daily and job run every day.

    we made one SP that Drop and recreate table with dynamic range partition according to number of rows(which we calculate count(*)).

    we made second SP that have all updates(around 30) which are dynamic with partition that has to apply while executing

    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 .
    

    This process repeat every day and it just took(30 minutes) with 40 million rows to execute all update.