DML操作常见问题

本文为您介绍对表执行DML操作过程中的常见问题。

问题类别

常见问题

插入或更新数据

删除数据

执行INSERT操作过程中出现错误,会损坏原有数据吗?

不会损坏原有数据。MaxCompute满足原子性,INSERT操作执行成功则更新数据,INSERT操作执行失败则回滚数据。

执行INSERT INTO或INSERT OVERWRITE操作时,提示Table xxx has n columns,but query has m columns,如何解决?

执行INSERT INTO或INSERT OVERWRITE操作插入数据时,需要保证SELECT得到的字段和目标表的字段匹配,匹配内容包括顺序、字段类型和总的字段数量。MaxCompute不支持插入表的指定字段,其他字段为NULL或者其他默认值时,您可以在SELECT时设置为NULL,例如select 'a', null, col_name from table_name;

执行INSERT INTO或INSERT OVERWRITE操作时,报错a single instance cannot output data to more than 10000 partitions,如何解决?

  • 问题现象

    在INSERT INTO或INSERT OVERWRITE操作时,返回报错如下。

    FAILED: ODPS-0123031:Partition exception - a single instance cannot output data to more than 10000 partitions
  • 产生原因

    虽然单个MaxCompute表允许有6万个分区,但是单个作业涉及的输出表分区数量只允许有10000个。出现这个错误,通常是因为分区字段设置有误,例如根据ID字段分区造成分区过多。

  • 解决措施

    一般作业输出动态分区数达到几千已经很大,超过10000可能存在业务逻辑或SQL语法问题。如无逻辑或语法问题,建议修改分区表的分区字段,或将业务逻辑拆分为多个作业,避免出现该错误。

向MaxCompute表中插入动态分区时,报错invalid dynamic partition value,如何解决?

  • 问题现象

    执行插入动态分区操作时,返回报错如下。

    FAILED: ODPS-0123031:Partition exception - invalid dynamic partition value: province=上海
  • 产生原因

    使用了非法的动态分区。动态分区是根据指定字段进行分区,不支持特殊字符和中文动态分区字段。

  • 解决措施

    插入动态分区时,需要注意如下情况:

    • 在分布式环境下执行插入动态分区操作时,单个进程最多只能输出512个动态分区。

    • 任意动态分区SQL不允许生成超过2000个动态分区。

    • 动态生成的分区值不允许为NULL。

    • 如果目标表有多级分区,在执行INSERT操作时,允许指定部分分区为静态,但是静态分区必须是高级分区。

向MaxCompute表中插入FLOAT类型的数据报错,如何解决?

MaxCompute 2.0支持的基本数据类型请参见数据类型版本说明。其中:FLOAT数据类型没有常量定义,若要插入该类型数据,可以使用CAST函数转换数据类型。例如cast(5.1 as float)将字符串'5.1'转为FLOAT类型5.1

MaxCompute SQL中使用到新数据类型(TINYINT、SMALLINT、INT、FLOAT、VARCHAR、TIMESTAMP或BINARY)时,需要执行如下语句开启新数据类型开关:

  • Session级别:如果使用新数据类型,您需要在SQL语句前加上set odps.sql.type.system.odps2=true;,并与SQL语句一起提交执行。

  • Project级别:执行setproject odps.sql.type.system.odps2=true;打开Project级别的新数据类型。该命令需要项目所有者执行。

对相同数据执行INSERT SELECT操作和SELECT操作的结果为什么不一致?

  • 问题现象

    对相同的STRING类型字段分别执行SQL语句,出现小数位不统一的现象。执行SELECT操作保留2位小数,执行INSERT SELECT操作,结果显示多个小数位。

  • 产生原因

    对于INSERT SELECT操作,原始字段类型是STRING,在隐式转换为目标类型DECIMAL的过程中,先转换为DOUBLE类型,然后在DOUBLE类型数据的基础上执行ROUND操作。由于DOUBLE类型本身是不精确的,虽然执行了ROUND操作,但是依然可能显示多个小数位。

  • 解决措施

    建议使用显式转换方式,增加如下语句通过CAST显示转换为DECIMAL类型。

    case when pcm.abc is null then 0 
                        else round(cast(pcm.abc as decimal) ,2) 
                    end abc                        

目标表的字段类型为VARCHAR(10),插入数据溢出时会报错吗?

VARCHAR(10)数据类型的字段插入数据时,数据长度溢出时会截断并不报错。

在执行MaxCompute SQL过程中,报错Transaction timeout because cannot acquire exclusive lock,如何解决?

  • 问题现象

    执行MaxCompute SQL的过程中,返回报错如下。

    Failed to run ddltask - Modify DDL meta encounter exception : ODPS-0121096:MetaStore transaction conflict - Reached maximum retry times because of OTSStorageTxnLockKeyFail(Inner exception: Transaction timeout because cannot acquire exclusive lock.) 
  • 产生原因

    MaxCompute允许多个作业同时写入数据到单个表。当多个作业同时处于元数据提交阶段时,每个作业都需要对单表表上的元数据加锁、写入、再解锁。如果同时多个作业写入,该表元数据总是处于加锁写入的状态,可能出现部分作业在尝试加锁超时之前一直没有抢到锁,从而导致报错 cannot acquire exclusive lock(作业尝试加锁超时时间大约半分钟,超过则报错,加锁粒度为表级)。简而言之,同时写表元数据的作业太多或者元数据写入量太大(如大量分区写入)时,并发写入同一张表元数据的另一个作业可能会加锁超时导致报错。

  • 解决措施

    您需要检查是否存在同时多次对表或表分区执行读写操作的情况,建议不要同时对一张表或表分区执行多次读写操作。

如何更新MaxCompute表或分区中的数据?

MaxCompute支持通过update操作,在行级别更新Transactional表中的数据。

如果表非Transactional表,您需要把源分区或源表中的数据导入到新分区或新表中,在导入过程中执行相应的更新逻辑操作。新分区或新表可以与源分区或源表相同,即就地更新。

如何删除MaxCompute表或分区中的数据?

MaxCompute支持通过delete操作,在行级别删除Transactional表中的数据。

如果表非Transactional表,您可以通过如下方法删除:

  • 执行drop命令删除表,达到删除数据的目的。

  • 如果是非分区表,您可以执行truncate table table_name;命令清空表数据或通过insert overwrite命令实现类似的功能。

    • 示例一:删除TableA表中Col=1的数据,命令示例如下。

      insert overwrite table TableA select a,b,c.... from TableA where Col <> 1;
    • 示例二:删除全部数据。

      insert overwrite table TableA select a,b,c.... from TableA where 1=2;
  • 如果是分区表,您可以执行alter table table_name drop if exists partition(分区名='具体分区值')命令,删除对应的分区,即可删除分区对应的数据。

    例如,表testtable的分区列为ds,执行如下命令删除ds='20170520'的分区。

    alter table testtable drop if exists partition (ds='20170520');
  • 使用INSERT和WHERE条件,将需要的数据导入到另一个新分区或新表中。INSERT支持源表和目标表相同。

    insert overwrite table sale_detail select * from sale_detail where name='mengyonghui';

如果表数据量较大,如何删除非分区表中的重复数据?

如果每一列都一样,您可以对所有列执行GROUP BY操作。例如,非分区表table1的列为c1,c2和c3,您可以执行如下命令。

insert overwrite table table1 select c1, c2, c3 from table1 group by

 c1, c2, c3;
说明

建议您在执行此操作前,做好数据备份工作并根据数据量评估此方式的代价是否比重新导入的代价低。