我的表名为tb_big
,大小为50 Gb。如果创建一个aditional列:
alter TABLE UAT_DM.ai_SUBS_MONTH_CLR ADD segment CHAR(5) not casespecific;
一切正常。所有值都为null,因此更新将非常快速(1分钟以上):
update tb_big
set segment = case when LT_month <= 4 then '0'
when LT_month <= 8 then '1'
when LT_month <= 12 then '2'
when LT_month <= 17 then '3'
when LT_month <= 24 then '4'
when LT_month <= 36 then '5'
when LT_month <= 56 then '6'
when LT_month <= 83 then '7'
when LT_month <= 96 then '8'
else '9' end;
所以我想说我想第二次更新同一列:
update tb_big
set segment = case when LT_month <= 4 then '0'
when LT_month <= 8 then '1'
when LT_month <= 12 then '2'
when LT_month <= 17 then '3'
when LT_month <= 27 then '42'
when LT_month <= 36 then '52'
when LT_month <= 56 then '6'
when LT_month <= 83 then '7'
when LT_month <= 96 then '08'
else '9' end;
由于大表大小和一些意外的TD行为,这样的更新将在事务下工作,因此每次更新都将记录到瞬态日志中,对于我来说不明原因将是高度倾斜(99.9%+)并且需要TB级别的假脱机。我差点把生产服务器放在膝盖上(TD管理员没有将它关闭并且优先完成并且无法备份,因为它可能需要很长时间才能回滚。这是真的吗?)
我的问题是如何正确更新大表?我的想法是删除该列并从头开始重复。但是我担心我不会再收到假脱机错误(see)。一个好的解决方案可能是创建新的空表并从第一个表复制除了要修改的列之外的所有列。但是采用x2空间并不是一个好习惯。
TD管理员的推荐不会更新更多200k行对我来说听起来很荒谬。
表的DDL,有500万行,大小为50 Gb:
CREATE MULTISET TABLE UAT_DM.ai_SUBS_MONTH_CLR ,NO FALLBACK ,
NO BEFORE JOURNAL,
NO AFTER JOURNAL,
CHECKSUM = DEFAULT,
DEFAULT MERGEBLOCKRATIO
(
CUST_ID DECIMAL(12,0),
LT_month DECIMAL(15,2),
days_to_LF(15,0),
REV_COM DECIMAL(18,6),
device_type VARCHAR(50) CHARACTER SET UNICODE CASESPECIFIC,
usg_qq DECIMAL(18,0),
usg_dd DECIMAL(18,6),
report_mnth CHAR(7) CHARACTER SET UNICODE NOT CASESPECIFIC,
MACN_ID DECIMAL(15,0),
segment CHAR(5) CHARACTER SET LATIN NOT CASESPECIFIC)
UNIQUE PRIMARY INDEX ( SUBS_ID ,report_mnth )
INDEX ( CUST_ID )
INDEX ( segment );
答案 0 :(得分:2)
你没有说出非常重要的细节。
首先,您添加了新列segment
,然后对其进行了更新。
然后您在segment
上创建了二级索引。
然后你运行第二次更新。
由于不同值的数量较少,此NUSI非常小。由于重复的数值很多,维护成本也很高(我从未测试过它,但这也应该是偏移瞬态期刊的原因)。
有一个经验法则(在大多数(所有?)DBMS中它是相似的):当它被编入索引时,不要更新大部分行列。
你通常这样做一次,然后你接到DBA的电话,你永远不会忘记:-)(当然它不应该是你最好分批更新)
在更新之前删除索引,然后重新创建它。
但为什么要在segment
上加上二级索引?优化器可能不会使用它,因为它的选择性很低。当然,您可以将CASE作为计算而不是列。
假设SUBS_ID
与CUST_ID
相同,您可以通过将主要索引更改为PRIMARY INDEX ( SUBS_ID )
来摆脱第二次NUSI,那可能不是很多每个SUBS_ID的行数。如果你使用report_mnth
访问很多,你可以按它进行分区(然后你最好把它改为INT,201805而不是&#39; 2018-05&#39;)。