Todos os produtos
Search
Central de documentação

MaxCompute:Reescreva instruções SQL incompatíveis

Última atualização: Jun 26, 2026

O MaxCompute V2.0 aplica regras de sintaxe SQL mais rigorosas para alinhar-se aos ecossistemas open-source e melhorar o desempenho. Algumas instruções executadas sem erros na V1.0 agora falham ou geram avisos na V2.0.

Este tópico aborda cada categoria de incompatibilidade, descreve o erro ou a mudança de comportamento e mostra como reescrever as instruções afetadas.

Antes de começar

Se o MaxCompute V2.0 não conseguir executar um job, o framework reverterá automaticamente para a V1.0. Essa reversão aumenta a latência do job. Para evitar que a reversão mascare problemas durante a migração, desative-a antes de enviar jobs:

set odps.sql.planner.mode=lot;

A equipe do MaxCompute notifica os proprietários dos jobs por e-mail ou DingTalk ao detectar reversões. Corrija as instruções afetadas o mais rápido possível para evitar falhas nos jobs após a remoção do suporte à reversão.

Referência rápida

Categoria

Descrição

group.by.with.star

SELECT * com GROUP BY exige todas as colunas na cláusula GROUP BY

bad.escape

Sequências de escape devem usar exatamente três dígitos octais

column.repeated.in.creation

Nomes de coluna duplicados em CREATE TABLE

duplicated.partition.column

Nomes de chave de partição duplicados em uma consulta

string.join.double

Conversão implícita de STRING para DOUBLE em condições JOIN

window.ref.prev.window.alias

Funções de janela não podem referenciar aliases de funções de janela irmãs

select.invalid.token.after.star

SELECT * não pode ter alias

agg.having.ref.prev.agg.alias

HAVING não pode usar aliases da cláusula SELECT

order.by.no.limit

ORDER BY exige cláusula LIMIT

generated.column.name.multi.window

Aliases de coluna gerados automaticamente podem mudar entre versões

non.boolean.filter

Expressões não BOOLEAN em filtros WHERE/HAVING

post.select.ambiguous

Referências de coluna ambíguas em ORDER BY / CLUSTER BY / DISTRIBUTE BY / SORT BY

order.by.col.ambiguous

ORDER BY referencia aliases duplicados em SELECT

in.subquery.without.result

Coluna na subconsulta IN não existe na tabela source

ctas.if.not.exists

Validação atual de erros de sintaxe na tabela de destino CTAS

dynamic.pt.to.static

Otimizador pode converter partições dinâmicas em estáticas

lot.not.in.subquery

Tratamento de NULL em subconsultas NOT IN

having.use.select.alias

HAVING não pode usar aliases de coluna definidos em SELECT

divide.nan.or.overflow

Constant folding de divisão causa erros para /0 no tempo de planejamento

small.table.exceeds.mem.limit

Hints MAPJOIN substituem a otimização de multi-way join

sigkill.oom

Tabelas pequenas grandes em MAPJOIN causam erros de falta de memória no worker

wm_concat.first.argument.const

Primeiro argumento de WM_CONCAT deve ser constante

pt.implicit.convertion.failed

Falha na conversão implícita de tipo em comparações de chave de partição

worker.restart.instance.timeout

Execução vetorizada de UDF causa timeouts de heartbeat

Instruções DDL

group.by.with.star

Na V1.0, SELECT * FROM t GROUP BY key era válido mesmo sem listar todas as colunas na cláusula GROUP BY. Na V2.0, cada coluna da tabela source deve aparecer na cláusula GROUP BY.

V1.0 (falha na V2.0):

select * from t group by key;

Erro:

FAILED: ODPS-0130071:[1,8] Semantic analysis exception - column reference t.value should appear in GROUP BY key

V2.0:

select distinct key from t;

Se a cláusula GROUP BY incluir todas as colunas, a instrução não gera erro na V2.0, mas a forma SELECT DISTINCT é mais clara:

-- Not recommended (no error, but intent is unclear)
select * from t group by key, value; -- t has columns key and value

-- Recommended
select distinct key, value from t;

column.repeated.in.creation

A V2.0 retorna erro quando uma instrução CREATE TABLE define o mesmo nome de coluna mais de uma vez. A V1.0 permitia essa definição.

V1.0 (falha na V2.0):

create table t (a BIGINT, b BIGINT, a BIGINT);

Erro:

FAILED: ODPS-0130071:[1,37] Semantic analysis exception - column repeated in creation: a

V2.0:

create table t (a BIGINT, b BIGINT);

duplicated.partition.column

Na V1.0, especificar a mesma chave de partição duas vezes mantinha silenciosamente o último valor. A V2.0 retorna erro.

V1.0 — valor de partição duplicado (falha na V2.0):

insert overwrite table t partition (ds = '1', ds = '2') select ...;
-- In V1.0, ds = '1' was silently ignored

V2.0:

insert overwrite table t partition (ds = '2') select ...;

V1.0 — coluna aparece tanto na definição da tabela quanto na partição (falha na V2.0):

create table t (a bigint, ds string) partitioned by (ds string);

V2.0:

create table t (a bigint) partitioned by (ds string);

ctas.if.not.exists

Na V1.0, se a tabela de destino já existisse, CREATE TABLE IF NOT EXISTS ... AS SELECT ignorava a validação de sintaxe. A V2.0 sempre valida a consulta; portanto, erros anteriormente ocultos agora aparecem.

V1.0 (falha na V2.0):

create table if not exists table_name
as
select * from not_exist_table;

Erro:

FAILED: ODPS-0130131:[1,50] Table not found - table meta_dev.not_exist_table cannot be resolved

Corrija a consulta referenciando uma tabela existente.

dynamic.pt.to.static

O otimizador da V2.0 pode converter partição dinâmica em estática durante o planejamento. Se o valor de partição inferido for inválido (por exemplo, variável não resolvida como '${bizdate}'), a V2.0 retorna erro durante a validação de sintaxe.

Exemplo de conversão:

-- Input
insert overwrite table srcpt partition(pt) select id, 'pt1' from table_name;

-- V2.0 converts this to:
insert overwrite table srcpt partition(pt='pt1') select id from table_name;

V1.0 (falha na V2.0 quando o valor da partição é inválido):

insert overwrite table srcpt partition(pt) select id, '${bizdate}' from table_name limit 0;

Erro:

FAILED: ODPS-0130071:[1,24] Semantic analysis exception - wrong columns count 2 in data source, requires 3 columns (includes dynamic partitions if any)

Na V1.0, LIMIT 0 não retornava linhas; logo, nenhuma partição era criada e nenhum erro ocorria. Na V2.0, o otimizador avalia a instrução antes da execução, o que aciona o erro.

Para mais informações, consulte o tópico Partition na documentação do MaxCompute.

Conversões de tipo

bad.escape

Em literais de string, escreva cada caractere ASCII (0–127) como barra invertida seguida por exatamente três dígitos octais (por exemplo, \001 para 0, \002 para 1). A V1.0 aceitava silenciosamente sequências fora do padrão, como \01 e \0001, tratando ambas como \001. A V2.0 as rejeita.

V1.0 (falha na V2.0):

select split(key, "\01"), value like "\0001" from t;

Erro:

FAILED: ODPS-0130161:[1,19] Parse exception - unexpected escape sequence: 01
ODPS-0130161:[1,38] Parse exception - unexpected escape sequence: 0001

V2.0:

select split(key, "\001"), value like "\001" from t;
Adicionar dígitos a \000 (como \0001 até \0009 , ou \00001 ) também aciona este erro.

string.join.double

Ao unir colunas STRING e DOUBLE, a V1.0 convertia ambas para BIGINT, causando perda de precisão (por exemplo, 1.1 = "1" era avaliado como igual). Seguindo a compatibilidade com Apache Hive, a V2.0 converte ambas para DOUBLE e emite aviso.

V1.0 (aciona aviso na V2.0):

select * from t1 join t2 on t1.double_value = t2.string_value;
Aviso
WARNING:[1,48]  implicit conversion from STRING to DOUBLE, potential data loss, use CAST function to suppress

V2.0:

select * from t1 join t2 on t1.double_value = cast(t2.string_value as double);

pt.implicit.convertion.failed

Ao filtrar coluna de partição STRING com constantes INT, a V1.0 convertia silenciosamente as constantes para DOUBLE para comparação, filtrando todos os valores de partição. A V2.0 retorna erro.

Considere a seguinte tabela:

create table srcpt(key STRING, value STRING) partitioned by (pt STRING);
alter table srcpt add partition (pt='pt1');
alter table srcpt add partition (pt='pt2');

V1.0 (falha na V2.0):

select key from srcpt where pt in (1, 2);

Erro:

FAILED: ODPS-0130071:[0,0] Semantic analysis exception - physical plan generation failed:
java.lang.NumberFormatException: ODPS-0123091:Illegal type cast -
In function cast, value 'pt1' cannot be casted from String to Double.

V2.0:

select key from srcpt where pt in ('1', '2');

Não compare colunas de partição STRING com constantes INT. Em vez disso, converta as constantes INT para STRING.

Mecanismo de consulta

window.ref.prev.window.alias

Função de janela não pode referenciar alias de outra função de janela na mesma cláusula SELECT. A V1.0 permitia isso em alguns casos; a V2.0 retorna erro.

V1.0 (falha na V2.0):

select row_number() over (partition by c1 order by c1) rn,
       row_number() over (partition by c1 order by rn) rn2
from t1;
-- rn does not exist in t1

Erro:

FAILED: ODPS-0130071:[2,45] Semantic analysis exception - column rn cannot be resolved

V2.0:

select row_number() over (partition by c1 order by rn) rn2
from (
  select c1, row_number() over (partition by c1 order by c1) rn
  from t1
) tmp;

select.invalid.token.after.star

SELECT * não aceita alias subsequente, mesmo quando * se expande para uma única coluna.

V1.0 (falha na V2.0):

select * as alias from table_test;

Erro:

FAILED: ODPS-0130161:[1,10] Parse exception - invalid token 'as'

V2.0:

select * from table_test;

agg.having.ref.select.alias

A avaliação da cláusula HAVING ocorre antes da cláusula SELECT. Aliases de coluna definidos em SELECT não estão disponíveis em HAVING.

V1.0 (falha na V2.0):

select count(c1) cnt,
       sum(c1) / cnt avg
from t1
group by c2
having cnt > 1;
-- cnt is a SELECT alias; it does not exist in source table t1

Erro:

FAILED: ODPS-0130071:[2,11] Semantic analysis exception - column cnt cannot be resolved
ODPS-0130071:[2,11] Semantic analysis exception - column reference cnt should appear in GROUP BY key

V2.0:

select cnt, s, s/cnt avg
from (
  select count(c1) cnt,
         sum(c1) s
  from t1
  group by c2
  having count(c1) > 1
) tmp;

having.use.select.alias

Conforme a especificação SQL, a avaliação de GROUP BY e HAVING precede SELECT; portanto, aliases da cláusula SELECT não são visíveis em HAVING.

V1.0 (falha na V2.0):

select id id2 from table_name group by id having id2 > 0;

Erro:

FAILED: ODPS-0130071:[1,44] Semantic analysis exception - column id2 cannot be resolved
ODPS-0130071:[1,44] Semantic analysis exception - column reference id2 should appear in GROUP BY key

id2 é alias da cláusula SELECT e não pode ser usado em HAVING.

V2.0:

select id id2 from table_name group by id having id > 0;

order.by.no.limit

No MaxCompute, ORDER BY classifica todas as linhas do conjunto de resultados, operação custosa para grandes volumes de dados. A V2.0 exige cláusula LIMIT acompanhando cada cláusula ORDER BY.

V1.0 (falha na V2.0):

select * from (
  select *
  from (
    select cast(login_user_cnt as int) as uv, '3' as shuzi
    from test_login_cnt where type = 'device' and type_name = 'mobile'
  ) v
  order by v.uv desc   -- missing LIMIT here
) v
order by v.shuzi limit 20;

Erro:

FAILED: ODPS-0130071:[4,1] Semantic analysis exception - ORDER BY must be used with a LIMIT clause

V2.0: Adicione cláusula LIMIT à subconsulta:

select * from (
  select *
  from (
    select cast(login_user_cnt as int) as uv, '3' as shuzi
    from test_login_cnt where type = 'device' and type_name = 'mobile'
  ) v
  order by v.uv desc limit 1000   -- example value; replace with a suitable limit for your data
) v
order by v.shuzi limit 20;

A V1.0 não aplicava essa regra para views criadas em projetos com odps.sql.validate.orderby.limit=false. Por exemplo, esta criação de view tinha sucesso na V1.0:

create view table_view as select id from table_view order by id;

Consultar essa view na V2.0 retorna:

FAILED: ODPS-0130071:[1,15] Semantic analysis exception - while resolving view xdj.xdj_view_limit - ORDER BY must be used with a LIMIT clause

Adicione cláusula LIMIT ao ORDER BY dentro da definição da view.

generated.column.name.multi.window

A V1.0 gerava automaticamente aliases para expressões em instruções SELECT. Esses aliases eram instáveis e podiam mudar entre versões do MaxCompute ou durante atualizações e reversões. A V2.0 alerta contra a dependência de aliases gerados automaticamente.

V1.0 (não recomendado):

select _c0 from (select count(*) from table_name) t;
-- _c0 is an auto-generated alias that may change

V2.0:

select c from (select count(*) c from table_name) t;

Sempre especifique aliases explícitos para colunas computadas.

non.boolean.filter

O MaxCompute não suporta conversões implícitas entre BOOLEAN e outros tipos. A V1.0 permitia valores BIGINT como condições de filtro em alguns casos; a V2.0 não permite.

V1.0 (falha na V2.0):

select id, count(*) from table_name group by id having id;

Erro:

FAILED: ODPS-0130071:[1,50] Semantic analysis exception - expect a BOOLEAN expression

V2.0:

select id, count(*) from table_name group by id having id <> 0;

post.select.ambiguous

Quando ORDER BY, CLUSTER BY, DISTRIBUTE BY ou SORT BY referencia nome que aparece tanto como coluna source quanto como alias da cláusula SELECT, a V1.0 selecionava silenciosamente a última coluna na lista SELECT. A V2.0 retorna erro.

V1.0 (falha na V2.0):

select a, b as a from t order by a limit 10;
-- a is ambiguous: it could be t.a or the alias for b

Erro:

FAILED: ODPS-0130071:[1,34] Semantic analysis exception - a is ambiguous, can be both t.a or null.a

V2.0:

select a as c, b as a from t order by a limit 10;

Esse erro também se aplica quando os nomes conflitantes referem-se à mesma coluna. Atualize instruções com nomes de coluna conflitantes para usar aliases inequívocos.

order.by.col.ambiguous

Quando ORDER BY referencia nome que aparece como alias duplicado na cláusula SELECT, a V2.0 retorna erro.

V1.0 (falha na V2.0):

select id, id
from table_test
order by id;

V2.0:

select id, id id2
from table_name
order by id;

Remova o alias duplicado antes de usar ORDER BY.

in.subquery.without.result

Se coluna referenciada em subconsulta IN não existir na tabela source, a V2.0 retorna erro de resolução de coluna mesmo que a subconsulta não retorne linhas.

V1.0 (falha na V2.0):

select * from table_name
where not_exist_col in (select id from table_name limit 0);

Erro:

FAILED: ODPS-0130071:[2,7] Semantic analysis exception - column not_exist_col cannot be resolved

Corrija o nome da coluna na cláusula WHERE.

lot.not.in.subquery

A V2.0 segue a semântica padrão de NULL do SQL para subconsultas IN e NOT IN:

  • 1 IN (NULL, 1, 2, 3) retorna TRUE

  • 1 IN (NULL, 2, 3) retorna NULL

  • NULL IN (NULL, 1, 2, 3) retorna NULL

Para NOT IN, se a subconsulta retornar qualquer valor NULL, o resultado será NULL (não TRUE) para cada linha não correspondente. A V1.0 retornava TRUE nesse caso.

Exemplo:

select * from t where c not in (select accepted from c_list);

Se accepted contiver valores NULL, esta consulta retornará resultados diferentes na V1.0 e na V2.0. Na V1.0, linhas onde c não corresponde a nenhum valor não NULL em accepted são retornadas. Na V2.0, a consulta não retorna linhas se accepted contiver quaisquer valores NULL.

V2.0 (exclua valores NULL explicitamente):

select * from t where c not in (select accepted from c_list where accepted is not null);

Verifique subconsultas usadas com NOT IN para confirmar se valores NULL no resultado da subconsulta correspondem ao comportamento desejado.

Constant folding

divide.nan.or.overflow

A V1.0 não avaliava subexpressões constantes durante o planejamento. Por exemplo, em IF(FALSE, 0/0, 1.0), a divisão nunca era executada porque a condição era falsa. A V2.0 realiza constant folding durante o planejamento, avaliando todas as subexpressões constantes — inclusive aquelas em ramificações que nunca serão executadas — e retorna erro se alguma produzir NaN ou overflow.

V1.0 (falha na V2.0):

select IF(FALSE, 0/0, 1.0) from table_name;

Erro (NaN):

FAILED: ODPS-0130071:[1,19] Semantic analysis exception - encounter runtime exception while evaluating function /,
detailed message: DIVIDE func result NaN, two params are 0.000000 and 0.000000

V1.0 (overflow):

select if(false, 1/0, 1.0) from table_name;

Erro (overflow):

FAILED: ODPS-0130071:[1,19] Semantic analysis exception - encounter runtime exception while evaluating function /,
detailed message: DIVIDE func result overflow, two params are 1.000000 and 0.000000

V2.0: Remova todas as expressões /0 e substitua-as por constantes válidas.

O mesmo problema se aplica a CASE WHEN. O otimizador move a divisão para subconsultas, onde o constant folding então a avalia:

V1.0:

select case when key = 0 then 0 else 1/key end
from (
  select 0 as key from src
  union all
  select key from src
) r;

Erro:

FAILED: ODPS-0130071:[0,0] Semantic analysis exception - physical plan generation failed:
java.lang.ArithmeticException: DIVIDE func result overflow, two params are 1.000000 and 0.000000

V2.0: Mova a lógica CASE WHEN para uma subconsulta e elimine a ramificação /0:

select c1
from (
  select 0 c1 from src
  union all
  select case when key = 0 then 0 else 1/key end c1 from src
) r;

Memória e UDFs

small.table.exceeds.mem.limit

Na V1.0, a otimização de multi-way join mesclava várias operações JOIN que compartilhavam a mesma chave de junção em uma única tarefa Fuxi, e hints MAPJOIN eram ignorados quando essa otimização se aplicava.

A V2.0 respeita hints MAPJOIN e os aplica primeiro. Se a tabela indicada for grande, o MAPJOIN excede o limite de memória de 640 MB e falha.

V1.0 (falha na V2.0):

select /* +mapjoin(t1) */ t1.*
from t1 join t2 on t1.c1 = t2.c1
join t3 on t1.c1 = t3.c1;

Erro:

FAILED: ODPS-0010000:System internal error - SQL Runtime Internal Error:
Hash Join Cursor HashJoin_REL… small table exceeds, memory limit(MB) 640,
fixed memory used …, variable memory used …

V2.0: Remova o hint MAPJOIN e permita que a V2.0 use a otimização de multi-way join:

select t1.*
from t1 join t2 on t1.c1 = t2.c1
join t3 on t1.c1 = t3.c1;

sigkill.oom

Este problema tem a mesma causa raiz que small.table.exceeds.mem.limit. Quando hints MAPJOIN estão presentes e as tabelas pequenas são grandes, a V1.0 revertia silenciosamente para a otimização de multi-way join. Na V2.0, o MAPJOIN é aplicado e o processo worker é encerrado ao exceder o limite de memória — mesmo que odps.sql.mapjoin.memory.max esteja definido.

Erro:

Fuxi job failed - WorkerRestart errCode:9,errMsg:SigKill(OOM), usually caused by OOM(out of memory).

V2.0: Remova hints MAPJOIN e confie na otimização de multi-way join.

wm_concat.first.argument.const

A assinatura da função WM_CONCAT exige que seu primeiro argumento (o separador) seja uma constante STRING:

string wm_concat(string separator, string str)

Na V1.0, essa restrição não era aplicada se a tabela source estivesse vazia. A V2.0 valida todos os argumentos durante o planejamento; portanto, um primeiro argumento não constante sempre falha.

V1.0 (falha na V2.0):

select wm_concat(value, ',') FROM src group by value;
-- value is a column reference, not a constant

Erro:

FAILED: ODPS-0130071:[0,0] Semantic analysis exception - physical plan generation failed:
com.aliyun.odps.lot.cbo.validator.AggregateCallValidator$AggregateCallValidationException:
Invalid argument type - The first argument of WM_CONCAT must be constant string.

V2.0:

select wm_concat(',', value) FROM src group by value;

Para mais informações, consulte o tópico Aggregate functions na Referência SQL do MaxCompute.

worker.restart.instance.timeout

Na V1.0, cada registro produzido por User-Defined Function (UDF) acionava gravação no Apsara Distributed File System e enviava heartbeat ao Job Scheduler. Se a UDF não produzisse registros por 10 minutos, o job atingia timeout.

A V2.0 usa execução vetorizada, processando múltiplas linhas de uma coluna por vez. Quando um lote de linhas leva mais de 10 minutos para produzir saída, o timeout de heartbeat é acionado mesmo que a UDF funcione corretamente.

Erro:

FAILED: ODPS-0123144: Fuxi job failed - WorkerRestart errCode:252,errMsg:kInstanceMonitorTimeout,
usually caused by bad udf performance.

Primeiro, analise o perfil da UDF. Se o processamento de cada registro levar vários segundos, otimize a lógica da UDF.

Se não for possível otimizar ainda mais a UDF, reduza o tamanho do lote. O tamanho padrão do lote é 1.024 linhas:

set odps.sql.executionengine.batch.rowcount=16;

Lotes menores são concluídos mais rapidamente e enviam heartbeats com maior frequência, evitando o timeout.