Todos os produtos
Search
Central de documentação

MaxCompute:Parquet external tables

Última atualização: Sep 18, 2026

Este tópico descreve como criar, ler e gravar dados em tabelas externas Parquet no Object Storage Service (OSS).

Escopo

Descrição de permissões

  • Ao acessar tabelas externas do OSS, o sistema utiliza a função especificada no parâmetro odps.properties.rolearn, seja com uma conta Alibaba Cloud, um usuário RAM ou uma função RAM. Portanto, crie uma função RAM, conceda permissões para acessar o bucket do OSS de destino e configure o ARN da função no parâmetro odps.properties.rolearn. Para mais informações, consulte Parâmetros.

  • Autorize o acesso na mesma conta ou entre contas diferentes, de acordo com os requisitos do seu negócio. Recomendamos o uso de uma política de autorização personalizada para um controle de acesso mais refinado. Para mais informações, consulte Autorização para fontes de dados externas.

Criar uma tabela externa

Sintaxe

Quando o schema do arquivo Parquet difere do schema da tabela externa:

  • Incompatibilidade na quantidade de colunas: se o arquivo Parquet tiver menos colunas do que as definidas na DDL da tabela externa, as colunas ausentes retornarão NULL. Se o arquivo tiver mais colunas, o sistema ignorará as colunas extras.

  • Incompatibilidade no tipo de coluna: se o tipo de uma coluna no arquivo Parquet não corresponder ao tipo correspondente na DDL, a operação de leitura falhará. Por exemplo, ocorrerá um erro como ODPS-0123131:User defined function exception - Traceback:xxx se você tentar ler uma coluna INT como um campo STRING.

Sintaxe simplificada

CREATE EXTERNAL TABLE [IF NOT EXISTS] <mc_oss_extable_name>
(
  <col_name> <data_type>,
  ...
)
[COMMENT <table_comment>]
[PARTITIONED BY (<col_name> <data_type>, ...)]
STORED AS parquet 
LOCATION '<oss_location>' 
[tblproperties ('<tbproperty_name>'='<tbproperty_value>',...)];

Sintaxe detalhada

CREATE EXTERNAL TABLE [IF NOT EXISTS] <mc_oss_extable_name>
(
  <col_name> <data_type>,
  ...
)
[COMMENT <table_comment>]
[PARTITIONED BY (<col_name> <data_type>, ...)]
ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe'
WITH serdeproperties(
    'odps.properties.rolearn'='acs:ram::<uid>:role/<role_name>',
    'mcfed.parquet.compression'='ZSTD/SNAPPY/GZIP'
)
STORED AS parquet 
LOCATION '<oss_location>' 
;

Parâmetros comuns

Para mais informações sobre os parâmetros comuns, consulte Parâmetros de sintaxe básica.

Parâmetros específicos

Parâmetros with serdeproperties

Nome da propriedade

Quando usar

Descrição

Valor da propriedade

Padrão

mcfed.parquet.compression

Adicione esta propriedade para gravar dados Parquet no OSS em formato compactado.

Propriedade de compactação do Parquet. Por padrão, os dados Parquet não são compactados.

  • ZSTD

  • SNAPPY

  • GZIP

Nenhum

mcfed.parquet.compression.codec.zstd.level

Adicione esta propriedade quando 'mcfed.parquet.compression'='zstd'. Caso não especifique esta propriedade, o sistema usará o nível de compactação padrão 3.

Um nível mais alto aumenta a taxa de compactação. No entanto, testes mostram que níveis altos proporcionam ganhos mínimos na redução do tamanho dos dados, ao mesmo tempo que aumentam significativamente o tempo e o consumo de recursos. Para cenários de big data, um nível baixo de ZSTD (3 a 5) oferece o melhor equilíbrio entre desempenho e compactação. Por exemplo: 'mcfed.parquet.compression.codec.zstd.level'= '5'.

O valor pode variar de 1 a 22.

3

parquet.file.cache.size

Adicione esta propriedade para melhorar o desempenho da leitura de arquivos de dados do OSS ao processar dados Parquet.

Especifica a quantidade de dados que o sistema pode armazenar em cache ao ler arquivos de dados do OSS. Unidade: KB.

1024

Nenhum

parquet.io.buffer.size

Adicione esta propriedade para melhorar o desempenho da leitura de arquivos de dados do OSS ao processar dados Parquet.

Especifica a quantidade de dados que o sistema pode armazenar em cache quando o tamanho do arquivo de dados do OSS excede 1024 KB. Unidade: KB.

4096

Nenhum

Parâmetros tblproperties

Nome da propriedade

Quando usar

Descrição

Valor da propriedade

Padrão

io.compression.codecs

Adicione esta propriedade se os seus arquivos de dados do OSS estiverem no formato Raw-Snappy.

Habilita o parser de código aberto integrado para o formato SNAPPY.

Se você definir este parâmetro como True, o MaxCompute poderá ler os dados compactados. Caso contrário, a operação de leitura falhará.

com.aliyun.odps.io.compress.SnappyRawCodec.

Nenhum

odps.external.data.output.prefix

(Compatível com odps.external.data.prefix)

Adicione esta propriedade para especificar um prefixo personalizado para os arquivos de saída.

  • Deve conter apenas letras, dígitos e sublinhados (a-z, A-Z, 0-9, _).

  • O comprimento deve ser de 1 a 10 caracteres.

Uma combinação válida de caracteres, como 'mc_'.

Nenhum

odps.external.data.enable.extension

Adicione esta propriedade para exibir a extensão dos arquivos de saída.

Defina como True para exibir a extensão do arquivo. Caso contrário, a extensão ficará oculta.

  • True

  • False

False

odps.external.data.output.suffix

Adicione esta propriedade para especificar um sufixo personalizado para os arquivos de saída.

Deve conter apenas letras, dígitos e sublinhados (a-z, A-Z, 0-9, _).

Uma combinação válida de caracteres, como '_hangzhou'.

Nenhum

odps.external.data.output.explicit.extension

Adicione esta propriedade para especificar uma extensão personalizada para os arquivos de saída.

  • Deve conter apenas letras, dígitos e sublinhados (a-z, A-Z, 0-9, _).

  • O comprimento deve ser de 1 a 10 caracteres.

  • Este parâmetro tem prioridade maior que odps.external.data.enable.extension.

Uma combinação válida de caracteres, como "jsonl".

Nenhum

odps.ext.column.mapping

Adicione esta propriedade quando os nomes dos campos nos arquivos de dados do OSS contiverem caracteres especiais.

Esta propriedade define mapeamentos personalizados de nomes de colunas. Por exemplo, se os campos do arquivo OSS forem id BIGINT, $_test DOUBLE e =name STRING, defina o valor do parâmetro como t_test:$_test,t_name:=_name ao criar a tabela externa. Você só precisa especificar mapeamentos para campos que contêm caracteres especiais.

Sem valor fixo

Nenhum

odps.ext.column.mapping.delimiters

(Use apenas quando os caracteres nos nomes das colunas entrarem em conflito com os delimitadores padrão nos mapeamentos de nomes de colunas. Geralmente não recomendado.)

Adicione esta propriedade quando os nomes das colunas contiverem os caracteres especiais : ou ,

Esta propriedade personaliza os delimitadores intra-grupo e inter-grupo para pares chave-valor. O valor deve conter exatamente dois caracteres: o primeiro caractere serve como delimitador chave-valor, e o segundo caractere serve como delimitador entre diferentes pares chave-valor.

Sem valor fixo. Exemplo: =|.

Valor padrão: ':,'

  • Por padrão, o sistema usa ':' como delimitador entre chaves e valores.

  • O sistema usa a vírgula ',' como delimitador entre diferentes pares chave-valor.

  • O sistema remove os espaços à esquerda e à direita nas chaves e valores durante a análise.

mcfed.parquet.compression

Adicione esta propriedade para gravar dados Parquet no OSS em formato compactado.

Nenhum parâmetro extra é necessário para ler arquivos compactados.

Propriedade de compactação do Parquet. Por padrão, os dados Parquet não são compactados.

  • SNAPPY

  • GZIP

  • ZSTD

Nenhum

mcfed.parquet.block.size

Controla o tamanho do bloco dos arquivos Parquet, o que afeta a eficiência de armazenamento e o desempenho de leitura.

Propriedade de ajuste do Parquet. Define o tamanho do bloco Parquet em bytes.

Inteiro não negativo

134217728 (128 MB)

mcfed.parquet.block.row.count.limit

Ao gravar dados em uma tabela externa Parquet, limita o número de registros em cada grupo de linhas para evitar erros de falta de memória (OOM).

Propriedade de ajuste do Parquet. Controla o número máximo de registros por grupo de linhas. Se ocorrer um erro OOM, reduza o valor deste parâmetro.

Sugestão:

  1. Se a memória da JVM for de apenas 1 GB e o tamanho médio do registro for de 1 MB, defina este parâmetro para cerca de 100. O tamanho padrão do grupo de linhas é de 128 MB.

  2. Não defina este parâmetro com um valor muito pequeno.

Inteiro não negativo

2147483647

(Integer.MAX_VALUE)

mcfed.parquet.page.size.row.check.min

Ao gravar dados em uma tabela externa Parquet, controla a frequência das verificações de memória para evitar erros OOM.

Propriedade de ajuste do Parquet. Limita o número mínimo de registros entre as verificações de memória. Se ocorrer um erro OOM, reduza o valor deste parâmetro.

Inteiro não negativo

100

mcfed.parquet.page.size.row.check.max

Ao gravar dados em uma tabela externa Parquet, controla a frequência das verificações de memória para evitar erros OOM.

Propriedade de ajuste do Parquet. Limita o número mínimo de registros entre as verificações de memória. Se ocorrer um erro OOM, reduza o valor deste parâmetro.

Como as verificações frequentes de memória adicionam sobrecarga, o ajuste deste parâmetro pode afetar o desempenho.

Recomendações de parâmetros:

  1. Por padrão, o sistema realiza uma verificação de memória a cada 10.000 registros. Se o tamanho do registro for pequeno, você pode definir este parâmetro com um valor menor, como 1000, para realizar verificações de memória com mais frequência e evitar erros OOM.

  2. Primeiro, tente reduzir o valor de mcfed.parquet.block.row.count.limit. Se os erros OOM persistirem ou os arquivos de saída forem muito grandes, reduza o valor de mcfed.parquet.page.size.row.check.max para verificar a memória com mais frequência.

Inteiro não negativo

1000

mcfed.parquet.compression.codec.zstd.level

Adicione esta propriedade para especificar o nível de compactação do algoritmo ZSTD ao gravar dados Parquet no OSS com compactação ZSTD.

Propriedade de compactação do Parquet. Especifica o nível de compactação do algoritmo ZSTD. O valor pode variar de 1 a 22.

Inteiro não negativo

3

Lista de permissões e lista de bloqueios

As tabelas externas do OSS no MaxCompute suportam filtragem por lista de permissões e lista de bloqueios. Defina os parâmetros de lista de permissões e lista de bloqueios em tblproperties para filtrar os arquivos a serem lidos de um diretório. Para mais detalhes, consulte Lista de permissões e lista de bloqueios.

Gravar dados

Para mais detalhes sobre a sintaxe de gravação no MaxCompute, consulte Sintaxe de gravação.

Consulta e análise

  • Consulte Sintaxe de consulta para obter detalhes sobre a sintaxe SELECT.

  • Consulte Otimização de consulta para obter detalhes sobre a otimização de planos de consulta.

  • Para mais informações sobre como ler arquivos LOCATION diretamente, consulte Consulta sem schema.

  • Otimização de consulta: as tabelas externas Parquet suportam otimização de consulta ao ativar o Predicate Push Down (PPD). Para resultados de desempenho, consulte Suporte ao Predicate Push Down (Parquet PPD).

    Adicione os seguintes parâmetros antes da sua instrução SQL para ativar o PPD:

    -- PPD parameters must be used in Native mode, which means the Native switch must be set to true.
    -- Enable the Parquet native reader.
    SET odps.ext.parquet.native = true; 
    -- Enable Parquet PPD.
    SET odps.sql.parquet.use.predicate.pushdown = true; 

Suporte ao Predicate Push Down (Parquet PPD)

Por padrão, as tabelas externas Parquet não suportam o Predicate Push Down (PPD). Quando você executa uma consulta com uma condição de filtro WHERE, o MaxCompute verifica todos os dados. Isso causa E/S desnecessária, consumo de recursos e latência de consulta. Para resolver esse problema, ative o PPD usando um parâmetro. Esse recurso utiliza os metadados nos arquivos Parquet para filtrar dados no nível do grupo de linhas durante a fase de verificação, o que melhora o desempenho da consulta e reduz o consumo de recursos e os custos.

Uso

  • Ativar o Predicate Push Down (PPD)

    Antes de executar uma consulta SQL, use o comando set para definir os dois parâmetros a seguir no nível da sessão e ativar o PPD para Parquet.

    -- Enable the Parquet native reader. 
    set odps.ext.parquet.native = true; 
    -- Enable Parquet PPD.
    set odps.sql.parquet.use.predicate.pushdown = true; 
  • Exemplo

    Este exemplo usa um conjunto de dados de teste TPC-DS de 1 TB e a tabela externa Parquet tpcds_1t_store_sales. Neste exemplo, com o PPD ativado, executamos uma consulta de filtro. O volume total de dados é de 2,879,987,999 linhas.

    -- Create the external table tpcds_1t_store_sales.
    CREATE EXTERNAL TABLE IF NOT EXISTS tpcds_1t_store_sales (
        ss_sold_date_sk         BIGINT,
        ss_sold_time_sk         BIGINT,
        ss_item_sk              BIGINT,
        ss_customer_sk          BIGINT,
        ss_cdemo_sk             BIGINT,
        ss_hdemo_sk             BIGINT,
        ss_addr_sk              BIGINT,
        ss_store_sk             BIGINT,
        ss_promo_sk             BIGINT,
        ss_ticket_number        BIGINT,
        ss_quantity             BIGINT,
        ss_wholesale_cost       DECIMAL(7,2),
        ss_list_price           DECIMAL(7,2),
        ss_sales_price          DECIMAL(7,2),
        ss_ext_discount_amt     DECIMAL(7,2),
        ss_ext_sales_price      DECIMAL(7,2),
        ss_ext_wholesale_cost   DECIMAL(7,2),
        ss_ext_list_price       DECIMAL(7,2),
        ss_ext_tax              DECIMAL(7,2),
        ss_coupon_amt           DECIMAL(7,2),
        ss_net_paid             DECIMAL(7,2),
        ss_net_paid_inc_tax     DECIMAL(7,2),
        ss_net_profit           DECIMAL(7,2)
    )
    ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe'
    WITH serdeproperties(
      'odps.properties.rolearn'='acs:ram::<uid>:role/<role_name>',
      'mcfed.parquet.compression'='zstd'
    )
    STORED AS parquet
    LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss_bucket_path/';
    -- Use the 1 TB TPC-DS test dataset.
    INSERT OVERWRITE TABLE tpcds_1t_store_sales
    SELECT 
        ss_sold_date_sk,
        ss_sold_time_sk,
        ss_item_sk,
        ss_customer_sk,
        ss_cdemo_sk,
        ss_hdemo_sk,
        ss_addr_sk,
        ss_store_sk,
        ss_promo_sk,
        ss_ticket_number,
        ss_quantity,
        ss_wholesale_cost,
        ss_list_price,
        ss_sales_price,
        ss_ext_discount_amt,
        ss_ext_sales_price,
        ss_ext_wholesale_cost,
        ss_ext_list_price,
        ss_ext_tax,
        ss_coupon_amt,
        ss_net_paid,
        ss_net_paid_inc_tax,
        ss_net_profit
    FROM 
        bigdata_public_dataset.tpcds_1t.store_sales;
    -- Run the query.
    SELECT SUM(ss_sold_date_sk) FROM tpcds_1t_store_sales
      WHERE ss_sold_date_sk >= 2451871 AND ss_sold_date_sk <= 2451880;

Comparação de desempenho

Ativar o PPD reduz a quantidade de dados verificados, o que diminui a latência da consulta e o consumo de recursos.

Modo

Total de linhas na tabela

Linhas verificadas

Bytes verificados

Tempo do Mapper

Consumo total de recursos

Descrição

Tabela externa Parquet sem PPD

2.879.987.999

2.879.987.999 (100%)

19386793984 (100%)

18s

CPU 19,25 Core-minutos, Memória 24,07 GB-minutos

100%

Tabela externa Parquet com PPD

2.879.987.999

762.366.649 (26,47%)

3.339.386.880 (17,22%)

12s

cpu 11,47 Core × Min, memória 14,33 GB × Min

~59,58%

A redução na verificação de dados diminui significativamente a latência e o consumo de recursos.

Tabela interna com PPD

2.879.987.999

32.830.000 (1,14%)

1.633.880.386 (8,43%)

9s

cpu 5,62 Core × Min, memória 7,02 GB × Min

~29,19%

O PPD é mais eficaz em tabelas internas porque os dados estão ordenados.

Detalhes do teste

  1. Tabela externa Parquet sem PPD

    SET odps.ext.parquet.native = true;
    SET odps.sql.parquet.use.predicate.pushdown = false;
    SELECT SUM(ss_sold_date_sk) FROM tpcds_1t_store_sales
      WHERE ss_store_sk = 2 AND ss_sold_date_sk >= 2451871 AND ss_sold_date_sk <= 2451880;

    image

    Os resultados mostram que, para a tarefa M1 em Fuxi Jobs, IO Records Input é 2,9 G, IO Bytes Input é 18,06 GB e Latency é 00:00:18.000.

    A aba Summary dos resultados de execução mostra que o consumo de recursos é cpu 19.25 Core × Min e memória 24.07 GB × Min. O tempo de execução do job é de 23.000 segundos, e o modo de execução é fuxi job 2.0. A tarefa M1 tem 1.404 instâncias, tempo de execução de 18.000 segundos, 2.879.987.999 registros de entrada e 355 registros de saída. A tarefa R2_1 tem 1 instância, tempo de execução de 4.000 segundos e 1 registro de saída.

  2. Tabela externa Parquet com PPD

    SET odps.ext.parquet.native = true;
    SET odps.sql.parquet.use.predicate.pushdown = true;
    SELECT SUM(ss_sold_date_sk) FROM tpcds_1t_store_sales
      WHERE ss_store_sk = 2 AND ss_sold_date_sk >= 2451871 AND ss_sold_date_sk <= 2451880;

    image

    Após executar esta consulta, o Summary do job mostra que o consumo de recursos é cpu 11.47 Core × Min, memory 14.33 GB × Min, com um tempo total de execução de 15 segundos. O estágio M1 tem 1.404 instâncias, tempo de execução de 12 segundos e 762.366.649 registros de entrada (aproximadamente 3.339.386.880 bytes). O estágio R2_1 tem 1 instância e tempo de execução de 3 segundos.

    Muitos mappers estão vazios e não precisam ler dados:

    image.webp

    Log do recorte real de grupos de linhas:

    [2024-05-10 22:29:22.692182]    [INFO]   [239551]    [/home/admin/odps_build/workspace/IRDS_CMK_7u/jenkins-IRDS_CMK_7u-70
    16/common/table/file_formats/parquet/parquet_row_group_pruner.cpp:100]    The expression to prune row groups:(((ss_store_s
    k == 2:int64) and (ss_sold_date_sk >= 2451871:int64)) and (ss_sold_date_sk <= 2451880:int64))
    [2024-05-10 22:29:22.705508]    [INFO]   [239551]    [/home/admin/odps_build/workspace/IRDS_CMK_7u/jenkins-IRDS_CMK_7u-70
    16/common/table/file_formats/parquet/parquet_reader_factory.cpp:136]    Parquet row group pruning is enabled, millisecon
    ds elapsed:13    Total row group count:1 Pruned row group count:1    The first several row group indexes:
    [2024-05-10 22:29:22.705532]    [INFO]   [239551]    [/home/admin/odps_build/workspace/IRDS_CMK_7u/jenkins-IRDS_CMK_7u-70
    16/common/table/file_formats/parquet/parquet_reader_factory.cpp:60]  total feasible parquet row group count:0]
  3. Tabela interna com PPD

    O efeito de recorte é mais significativo porque os dados na tabela interna estão ordenados.

    SELECT SUM(ss_sold_date_sk) FROM bigdata_public_dataset.tpcds_1t.store_sales
      WHERE ss_store_sk = 2 AND ss_sold_date_sk >= 2451871 AND ss_sold_date_sk <= 2451880;

    Após executar esta consulta, o DAG do job mostra que o número total de linhas na fonte de dados é 2.879.987.999, mas o número real de linhas verificadas é de apenas 32.830.000. O estágio M1 (703 instâncias) lê 32.830.000 linhas e gera 323 linhas. O estágio R2_1 recebe 323 linhas e gera 1 linha. Isso mostra que o efeito de recorte é significativo quando o PPD está ativado para uma tabela interna com dados ordenados.

    O monitoramento do Fuxi Jobs mostra que o job SQL_0_1_0_job_0 foi concluído. Ele inclui duas Fuxi Tasks, M1 e R2_1, ambas com status Terminated. M1 tem 703 instâncias, entrada de 32,8M registros (1,52 GB), saída de 323 registros e latência de 00:00:09.375. R2_1 tem 1 instância, entrada de 323 registros, saída de 1 registro e latência de 00:00:03.873. Os detalhes da instância M1 mostram 4 instâncias Data-Skew. Instâncias como M1#101_0, M1#103_0 e M1#105_0 têm 0 tanto para Input quanto para Output. Isso indica que são instâncias de dry-run e que esta consulta tem um problema de data skew.

    resource cost: cpu 5.62 Core * Min, memory 7.02 GB * Min
    inputs:
        lakehouse47_2.default.tpcds_1t_store_sales2: 32830000 (1633880386 bytes)
    outputs:
    Job run time: 14.000
    Job run mode: fuxi job 2.0
    Job run engine: execution engine
    M1:
        instance count: 703
        run time: 9.000
        instance time:
            min: 0.000, max: 2.000, avg: 0.000
        input records:
            TableScan1: 32830000  (min: 0, max: 210000, avg: 46699)
        output records:
            StreamLineWrite1: 323  (min: 0, max: 1, avg: 0)
        metrics_output_count:
            Calc1: 58025  (min: 0, max: 461, avg: 82)
            HashAgg1: 323  (min: 0, max: 1, avg: 0)
            StreamLineWrite1: 323  (min: 0, max: 1, avg: 0)
            TableScan1: 32830000  (min: 0, max: 210000, avg: 46699)
        metrics_inner_time_ms:
            Calc1: 4  (min: 0, max: 2, avg: 0)  MaxInstance: 21
            GlobalInit: 57752  (min: 60, max: 386, avg: 82)  MaxInstance: 17
            HashAgg1: 0  (min: 0, max: 0, avg: 0)   MaxInstance: 2
            StreamLineWrite1: 20469  (min: 5, max: 899, avg: 29)   MaxInstance: 400
            TableScan1: 131977  (min: 51, max: 1417, avg: 187)  MaxInstance: 301
    R2_1:
        instance count: 1
        run time: 4.000
        instance time:
            min: 0.000, max: 0.000, avg: 0.000
        input records:
            StreamLineRead1: 323  (min: 323, max: 323, avg: 323)
        output records:
            AdhocSink1: 1  (min: 1, max: 1, avg: 1)
        metrics_output_count:
            AdhocSink1: 1  (min: 1, max: 1, avg: 1)

Comparação de desempenho entre Parquet e ZSTD

A seção a seguir compara o desempenho de diferentes formatos de compactação para tabelas externas Parquet.

Nota: Os resultados dos testes são apenas para referência. O desempenho pode variar de acordo com o cenário de negócio. Recomendamos realizar mais testes e avaliações para o seu caso de uso específico.

Desempenho de consulta

Conjunto de dados: TPC-DS 1 TB
Recursos: mais de 900 CU
Método de teste: ETL

Métrica

Parquet sem compactação

Parquet-Snappy

Parquet-ZSTD

tempo de execução do job (s)

4372

4215

3649

Custo de CPU

14.211,89

10.131,36

6.004,26

Custo de memória

26.852,91

19.323,27

11.778,06

Armazenamento (GB)

425,94

335,33

230,87

  • Latência: o ZSTD é 13,4% mais rápido que o Snappy e 16,5% mais rápido que o formato sem compactação.

  • CPU: o ZSTD usa 40,7% menos CPU que o Snappy e 57,75% menos que o formato sem compactação.

  • Memória: o ZSTD usa 39,04% menos memória que o Snappy e 56,13% menos que o formato sem compactação.

  • Armazenamento: o ZSTD usa 31,15% menos armazenamento que o Snappy e 45,8% menos que o formato sem compactação.

imageimageimage

Eficiência de armazenamento

Conjunto de dados: TPC-DS 1 TB
Recursos: mais de 900 CU
Método de teste: ETL
  • sem compactação: embora este formato não seja compactado, ele resulta em volumes de dados maiores e maior sobrecarga de E/S, o que leva a um desempenho geral ruim.

  • snappy: a velocidade de compactação não é mais rápida que a do ZSTD de nível baixo, mas a taxa de compactação é maior. Isso resulta em um desempenho geral inferior ao do ZSTD de nível baixo.

  • zstd: o tamanho dos dados de saída converge rapidamente. Níveis mais altos proporcionam uma compactação adicional mínima (apenas 13,87% a mais), mas causam um aumento rápido no tempo e no consumo de recursos, o que reduz drasticamente a relação custo-benefício. Para este cenário, o ZSTD de nível baixo (níveis 3 a 5) oferece os melhores resultados. O nível 3 é o padrão.

  • No conjunto de dados TPC-DS de 1 TB, o ZSTD usou 31,1% menos espaço de armazenamento que o Snappy e 45,8% menos que o formato sem compactação.

Formato de compactação

Tamanho dos dados de saída (GB / Taxa de compactação)

Tempo de execução do job (s)

Tempo do TableSink (s, % do tempo de execução do job)

CPU (Core × Min)

Memória (GB × Min)

sem compactação

486,67 (100%)

256,406

~ 134,61 (52,5%)

2.353,19

3.361,71

snappy

238,33 (48,97%)

239,087

~ 73,88 (30,9%)

2.110,31

3.014,73

zstd (nível 1, mín)

164,71 (33,84%)

233,170

~ 65,75 (28,2%)

2.110,23

3.014,61

zstd (nível 2)

165,3 (33,97%)

231,226

~ 64,51 (27,9%)

2.100,79

3.001,13

zstd (nível 3, padrão)

158,9 (32,65%)

236,985

~ 67,07 (28,3%)

2.115,10

3.021,57

zstd (nível 4)

159,52 (32,77%)

232,477

~ 67,65 (29,1%)

2.100,13

3.000,19

zstd (nível 5)

157,89 (32,44%)

232,248

~ 71,07 (30,6%)

2.103,96

3.005,66

zstd (nível 6)

160,47 (32,97%)

236,669

~ 78,10 (33,0%)

2.137,63

3.053,75

zstd (nível 9)

152,00 (31,23%)

254,073

~ 100,36 (39,5%)

2.287,61

3.268,01

zstd (nível 14)

144,63 (29,72%)

455,019

~ 341,26 (75,5%)

4.076,00

5.822,86

zstd (nível 19)

150,87 (31,00%)

727,841

~ 614,30 (84,4%)

6.933,10

9.904,43

zstd (nível 22, máx)

150,81 (30,99%)

5.381,359

~ 5.257,59 (97,7%)

42.848,13

61.211,62

image

Cenário de exemplo

Este exemplo mostra como criar uma tabela externa Parquet particionada com compactação ZSTD e, em seguida, ler e gravar dados na tabela.

  1. Pré-requisitos

    1. Você criou um projeto MaxCompute. Para mais informações, consulte Criar um projeto MaxCompute.

    2. Você preparou um bucket e um diretório no OSS. Para mais informações, consulte Criar um bucket e Gerenciar diretórios.

      Certifique-se de que o seu bucket esteja na mesma região do seu projeto MaxCompute.
    3. Conceda permissões.

      1. Tenha permissão para acessar o OSS. Utilize uma conta Alibaba Cloud, um usuário RAM ou uma função RAM para acessar a tabela externa do OSS. Para mais informações sobre como conceder permissões, consulte Autorização no modo STS para OSS.

      2. Tenha a permissão CreateTable no projeto MaxCompute. Para mais informações sobre permissões relacionadas a tabelas, consulte Permissões do MaxCompute.

  2. Prepare um arquivo de dados no formato ZSTD.

    No bucket oss-mc-test para os dados de amostra, crie a pasta parquet_zstd_jni/dt=20230418 e armazene o arquivo de dados na pasta da partição dt=20230418.

  3. Crie uma tabela externa Parquet que use o formato de compactação ZSTD.

    CREATE EXTERNAL TABLE IF NOT EXISTS mc_oss_parquet_data_type_zstd (
        vehicleId INT,
        recordId INT,
        patientId INT,
        calls INT,
        locationLatitute DOUBLE,
        locationLongtitue DOUBLE,
        recordTime STRING,
        direction STRING
    )
    PARTITIONED BY (dt STRING )
    ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe'
    WITH serdeproperties(
      'odps.properties.rolearn'='acs:ram::<uid>:role/<role_name>',
      'mcfed.parquet.compression'='zstd'
    )
    STORED AS parquet
    LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/parquet_zstd_jni/';
  4. Importe os dados da partição. Se a tabela externa do OSS for uma tabela particionada, importe também os dados da partição. Para mais informações, consulte Tabelas externas do OSS.

    -- Import partition data.
    MSCK REPAIR TABLE mc_oss_parquet_data_type_zstd ADD PARTITIONS;
  5. Leia os dados da tabela externa Parquet.

    SELECT * FROM mc_oss_parquet_data_type_zstd WHERE dt='20230418' LIMIT 10;

    O sistema retorna o seguinte exemplo de saída:

    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+------------+
    | vehicleid  | recordid   | patientid  | calls      | locationlatitute | locationlongtitue | recordtime     | direction  | dt         |
    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+------------+
    | 1          | 12         | 76         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:10 | SW         | 20230418   |
    | 1          | 1          | 51         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:00 | S          | 20230418   |
    | 1          | 2          | 13         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:01 | NE         | 20230418   |
    | 1          | 3          | 48         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:02 | NE         | 20230418   |
    | 1          | 4          | 30         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:03 | W          | 20230418   |
    | 1          | 5          | 47         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:04 | S          | 20230418   |
    | 1          | 6          | 9          | 1          | 46.81006         | -92.08174         | 9/14/2014 0:05 | S          | 20230418   |
    | 1          | 7          | 53         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:06 | N          | 20230418   |
    | 1          | 8          | 63         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:07 | SW         | 20230418   |
    | 1          | 9          | 4          | 1          | 46.81006         | -92.08174         | 9/14/2014 0:08 | NE         | 20230418   |
    | 1          | 10         | 31         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:09 | N          | 20230418   |
    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+------------+
  6. Grave dados na tabela externa Parquet.

    INSERT INTO mc_oss_parquet_data_type_zstd PARTITION ( dt = '20230418') 
      VALUES  (1,16,76,1,46.81006,-92.08174,'9/14/2014 0:10','SW');
    -- Query the newly written data
    SELECT * FROM mc_oss_parquet_data_type_zstd WHERE dt = '20230418' AND recordid=16;

    O resultado é o seguinte:

    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+------------+
    | vehicleid  | recordid   | patientid  | calls      | locationlatitute | locationlongtitue | recordtime     | direction  | dt         |
    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+------------+
    | 1          | 16         | 76         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:10 | SW         | 20230418   |
    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+------------+

Tipos de dados suportados

Para mais informações sobre os tipos de dados do MaxCompute, consulte Tipos de dados (versão 1.0) e Tipos de dados (versão 2.0).

  • Modo Java Native Interface (JNI): set odps.ext.parquet.native=false. Este modo usa a implementação original de código aberto baseada em Java para analisar arquivos de dados Parquet ao ler de uma tabela externa. Ele suporta operações de leitura e gravação.

  • Modo Nativo: set odps.ext.parquet.native=true. Este modo usa a nova implementação nativa baseada em C++ para analisar arquivos de dados Parquet ao ler de uma tabela externa. Ele suporta apenas operações de leitura.

    Modo

    Modo Java (leitura/gravação)

    Modo Nativo (somente leitura)

    TINYINT

    Suportado

    Suportado

    SMALLINT

    Suportado

    Suportado

    INT

    Suportado

    Suportado

    BIGINT

    Suportado

    Suportado

    BINARY

    Suportado

    Suportado

    FLOAT

    Suportado

    Suportado

    DOUBLE

    Suportado

    Suportado

    DECIMAL(precision,scale)

    Não suportado

    Suportado

    VARCHAR(n)

    Suportado

    Suportado

    CHAR(n)

    Suportado

    Suportado

    STRING

    Suportado

    Suportado

    DATE

    Suportado

    Suportado

    DATETIME

    Suportado

    Suportado

    TIMESTAMP

    Suportado

    Suportado

    TIMESTAMP_NTZ

    Não suportado

    Não suportado

    BOOLEAN

    Suportado

    Suportado

    ARRAY

    Suportado

    Suportado

    MAP

    Suportado

    Suportado

    STRUCT

    Suportado

    Suportado

    JSON

    Não suportado

    Não suportado

Formatos de compactação suportados

Para ler ou gravar arquivos compactados do OSS, adicione a configuração da propriedade with serdeproperties à instrução de criação da tabela. Para mais informações, consulte Parâmetros da propriedade with serdeproperties.

Propriedade de compactação

Leitura

Gravação

Gzip

Suportado

Suportado

ZSTD

Suportado

Suportado

SNAPPY (SnappyRawCodec)

Suportado

Suportado

SNAPPY (SnappyCodec)

Suportado

Não suportado

Suporte à evolução de schema

As tabelas externas Parquet mapeiam os valores das colunas entre o schema e as colunas do arquivo por nome.

A coluna Problemas de compatibilidade de dados na tabela a seguir descreve se a leitura dos dados ocorre corretamente após uma operação de evolução de schema. Isso se aplica tanto a novos dados que estão em conformidade com o schema modificado quanto a dados históricos que usam o schema antigo.

Tipo de operação

Suportado

Descrição

Problemas de compatibilidade de dados

Adicionar coluna

Suportado

  • O sistema adiciona novas colunas no final da tabela. Você não pode especificar a posição delas.

  • Se você adicionar uma coluna com um valor padrão, o valor padrão se aplicará apenas aos dados gravados pelo MaxCompute.

  • O sistema lê dados que correspondem ao schema modificado.

  • Se você não modificar as colunas dos dados existentes que usam o schema antigo, o sistema lerá a tabela usando o novo schema.

    Por exemplo, se você adicionar uma coluna, o sistema lerá os dados históricos dessa coluna como NULL.

Excluir coluna

Suportado

As tabelas externas Parquet mapeiam os valores das colunas por nome.

Compatível

Reordenar colunas

Suportado

As tabelas externas Parquet mapeiam os valores das colunas por nome.

Compatível

Alterar o tipo de dados da coluna

Não suportado

O sistema não suporta esta operação. O formato Parquet possui validação rigorosa de schema. Alterar um tipo de dados pode tornar os dados ilegíveis.

Não aplicável

Renomear coluna

Não suportado

O sistema não suporta esta operação. O formato Parquet possui validação rigorosa de schema, o que pode fazer com que tipos anteriormente compatíveis se tornem ilegíveis após a modificação.

Não aplicável

Modificar o comentário da coluna

Suportado

O comentário deve ser uma string válida com no máximo 1024 bytes. Caso contrário, ocorrerá um erro.

Compatível

Modificar a propriedade não nula de uma coluna

Não suportado

O sistema não suporta esta operação. As colunas são anuláveis por padrão.

Não aplicável

FAQ

Tipos de coluna incompatíveis entre um arquivo Parquet e uma DDL de tabela externa

  • Mensagem de erro

    ODPS-0123131:User defined function exception - Traceback:
    java.lang.ClassCastException: org.apache.hadoop.io.LongWritable cannot be cast to org.apache.hadoop.io.IntWritable 
       at org.apache.hadoop.hive.serde2.objectinspector.primitive.WritableIntObjectInspector.getPrimitiveJavaObject(WritableIntObjectInspector.java:46)
  • Descrição do erro

    O tipo de campo LongWritable do arquivo Parquet não corresponde ao tipo INT na DDL da tabela externa.

  • Solução

    Altere o tipo INT na DDL da tabela externa para BIGINT.

Erro ao gravar em uma tabela externa: java.lang.OutOfMemoryError

  • Mensagem de erro

    ODPS-0123131:User defined function exception - Traceback:
    java.lang.OutOfMemoryError: Java heap space
    	at java.io.ByteArrayOutputStream.<init>(ByteArrayOutputStream.java:77)
    	at org.apache.parquet.bytes.BytesInput$BAOS.<init>(BytesInput.java:175)
    	at org.apache.parquet.bytes.BytesInput$BAOS.<init>(BytesInput.java:173)
    	at org.apache.parquet.bytes.BytesInput.toByteArray(BytesInput.java:161)
  • Descrição do erro

    Ocorre um erro de falta de memória (OOM) quando você grava um grande volume de dados em uma tabela externa Parquet.

  • Solução

    Ao criar uma tabela externa, primeiro diminua o parâmetro mcfed.parquet.block.row.count.limit. Se um erro OOM ainda ocorrer ou o arquivo de saída for muito grande, diminua o parâmetro mcfed.parquet.page.size.row.check.max para verificar a memória com mais frequência. Para mais informações, consulte Parâmetros específicos.

    Antes de gravar dados na tabela externa Parquet, adicione os seguintes parâmetros.

    -- Set the maximum memory size for the UDF JVM heap.
    SET odps.sql.udf.jvm.memory=12288;
    -- Control the batch size on the runtime side.
    SET odps.sql.executionengine.batch.rowcount =64;
    -- Set the memory size for each Map worker.
    SET odps.stage.mapper.mem=12288;
    -- Set the input data volume for each Map worker (input file shard size) to indirectly control the number of workers per Map stage.
    SET odps.stage.mapper.split.size=64;