我们在花费很长时间的单个表上进行更新时遇到了麻烦。该表包含约3000万行。
该作业每天都会运行,它会截断表并从该表中的其他其他来源插入新数据。
这是桌子:
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);
这两个之间有很多更新,但是花费的时间更少。 原因只有两个索引,因为所有上述查询都会更新整个表(4000万条记录)。所以我认为不需要索引。
每次更新大约需要25分钟。服务器具有足够的Ram可用于所有操作。 我已经尝试过临时表,但是性能没有任何改善,因为整个表的更新都没有分区逻辑可以帮助我。
我正在Windows 10上运行此查询。是否可以提高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.
使用一个表进行其他更新很简单,因此我认为不需要解释。
答案 0 :(得分:0)
例如,使用LIMIT 1000将UPDATE拆分为块(limit适用于UPDATE查询)。
例如:
UPDATE TempPortFolio1
SET Age = DATEDIFF(NAVDATE, TR_DATE),
CurrAmt = (LatestNav * Units),
PL_Notional = (UNITS * (LatestNav - Rate)),
Divd_Recd = 0 LIMIT 1000;
答案 1 :(得分:0)
使用PRIMARY KEY
浏览表。一次检查1000行。详细讨论here
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..64K)可能是合适的。DOUBLE
占用8个字节,并且由于在二进制和十进制之间切换而冒着额外舍入的风险。通常,进行大量更新是不良的架构设计的标志,因为这意味着“值”不是一个位置,而是数百万个位置。冗余在数据库中是不可以的。
返回慢速UPDATE
。有什么问题:
UPDATE
所获得的。)答案 2 :(得分:0)
想要知道的人的答案。
因此,随着数据每天被截断/插入并且每天都会运行作业。
我们制作了一个SP,该SP根据行数(我们计算count(*))删除并重新创建具有动态范围分区的表。
我们制作了第二个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分钟(4000万行)就完成了所有更新。