Replicação SQLite3 -> PostgreSQL

Objetivo

Replicar um banco de metadados do Superset de SQLite3 para PostgreSQL.

Dependências

[1] Docker, 26.0.0
[2] Superset, 3.1.0

Motivação

A versão padrão de desenvolvimento do Superset vem com SQLite3 como sistema de gerenciamento para seu banco de dados de metadados. Siga esse guia caso haja dashboards desenvolvidos nessa versão e seja necessário replicar o banco para um banco em PostgreSQL.

Atenção: esse guia funciona (ou, pelo menos, funcionou) para replicar exatamente de um banco para o outro, e não preserva as informações que já existirem no banco em PostgreSQL.

Replicação

  1. Faça um backup do banco de dados: cp superset.db superset.db.bkp;

  2. Existem algumas maneiras de migrar do SQLite para Postgres. O mais simples é fazer um dump de todas as tabelas do banco para CSV. Porém, precisamos nos atentar para determinados tipos de colunas que dão problema com o Postgres. Por exemplo, as colunas uuid são armazenadas em binário, e precisamos convertê-las para hexadecimal. Usei um script como esse (deve ser rodado sob usuário root.):

#!/bin/sh
set -e

# diretório para armazenar os csv gerados
mkdir bkp

# nomes da maioria das tabelas do banco de metadados do Superset
TABELAS="ab_permission report_schedule ab_permission_view report_schedule_user ab_permission_view_role rls_filter_roles ab_register_user rls_filter_tables ab_role row_level_security_filters ab_user saved_query ab_user_role sl_columns ab_view_menu sl_dataset_columns alembic_version sl_dataset_tables annotation sl_dataset_users annotation_layer sl_datasets cache_keys sl_table_columns css_templates sl_tables dashboard_roles slice_user dashboard_slices slices dashboard_user sql_metrics dashboards sqlatable_user dbs ssh_tunnels dynamic_plugin tab_state embedded_dashboards table_columns favstar table_schema filter_sets tables"

for tabela in $TABELAS; do
    # imprimir nomes das colunas na tabela, transformar em uma linha separada por
    # vírgulas, envolver todos os nomes em aspas duplas, e substituir "uuid" por hex(uuid).
    colunas=$(sqlite3 -csv superset.db "SELECT name FROM pragma_table_info('$tabela');" | awk '$1=$1' RS= OFS=\",\" | sed 's/\"uuid\"/hex(uuid)/')
    colunas="\"${colunas}\""
    sqlite3 -header -csv superset.db "SELECT $colunas FROM $tabela;" > bkp/$tabela.csv
    echo "Tabela $tabela exportada."
done

# tabela key_value é especial porque contém uma coluna "value" que também deve ser convertida para hex.
colunas=$(sqlite3 -csv superset.db "SELECT name FROM pragma_table_info('key_value');" | awk '$1=$1' RS= OFS=\",\" | sed 's/\"uuid\"/hex(uuid)/' | sed 's/\"value\"/hex(value)/')
colunas="\"${colunas}\""
sqlite3 -header -csv superset.db "SELECT $colunas FROM key_value;" > bkp/key_value.csv
echo "Tabela key_value exportada."

# resto das tabelas
TABELAS="tag keyvalue tagged_object logs url query user_attribute report_execution_log user_favorite_tag"

for tabela in $TABELAS; do
    colunas=$(sqlite3 -csv superset.db "SELECT name FROM pragma_table_info('$tabela');" | awk '$1=$1' RS= OFS=\",\" | sed 's/\"uuid\"/hex(uuid)/')
    colunas="\"${colunas}\""
    sqlite3 -header -csv superset.db "SELECT $colunas FROM $tabela;" > bkp/$tabela.csv
    echo "Tabela $tabela exportada."
done
  1. Use o comando COPY do Postgres para copiar as tabelas em CSV para dentro do banco de dados. OBS: Nesse momento as tabelas no Postgres devem estar criadas e vazias. Se houver dados, é necessário truncar as tabelas. Usei os seguintes scripts (com as informações necessárias preenchidas) (devem ser rodados sob o superusuário do Postgres):

#!/bin/sh

set -e

TABELAS="ab_permission report_schedule ab_permission_view report_schedule_user ab_permission_view_role rls_filter_roles ab_register_user rls_filter_tables ab_role row_level_security_filters ab_user saved_query ab_user_role sl_columns ab_view_menu sl_dataset_columns alembic_version sl_dataset_tables annotation sl_dataset_users annotation_layer sl_datasets cache_keys sl_table_columns css_templates sl_tables dashboard_roles slice_user dashboard_slices slices dashboard_user sql_metrics dashboards sqlatable_user dbs ssh_tunnels dynamic_plugin tab_state embedded_dashboards table_columns favstar table_schema filter_sets tables key_value tag keyvalue tagged_object logs url query user_attribute report_execution_log user_favorite_tag"

for tabela in $TABELAS; do
    psql -U usuario_no_postgres -d banco_de_metadados_superset -c "TRUNCATE $tabela CASCADE;"
done
#!/bin/sh

set -e

# nessa etapa, a ordem de cópia das tabelas é importante porque elas possuem dependências umas com as outras.
# não mude a ordem em que as tabelas aparecem nessa string.
TABELAS="ab_permission report_schedule ab_view_menu ab_permission_view report_schedule_user ab_role ab_permission_view_role rls_filter_roles ab_register_user rls_filter_tables row_level_security_filters ab_user dbs saved_query ab_user_role sl_columns sl_dataset_columns alembic_version sl_dataset_tables annotation sl_dataset_users annotation_layer sl_datasets cache_keys sl_table_columns css_templates sl_tables dashboard_roles slices slice_user dashboards dashboard_slices dashboard_user tables sql_metrics sqlatable_user ssh_tunnels dynamic_plugin query tab_state embedded_dashboards table_columns favstar table_schema filter_sets key_value tag keyvalue tagged_object logs url user_attribute report_execution_log user_favorite_tag"

for tabela in $TABELAS; do
    psql -U usuario_no_postgres -d banco_de_metadados_superset -c "COPY $tabela FROM '/app/superset_home/bkp/$tabela.csv' DELIMITER ',' CSV HEADER;"
done

Com todas as tabelas copiadas, reinicie o Superset. Você deve poder acessar agora os usuários, papéis, dashboards e gráficos criados anteriormente (dado que o Superset tenha acesso ao mesmo banco usado para criar os gráficos originalmente).