Pular para o conteúdo principal

Consultar bancos de dados usando JDBC

important

A documentação antiga da federação de consultas foi retirada e pode não ser atualizada. O produto, o serviço ou a tecnologia mencionados neste conteúdo não são oficialmente endossados ou testados pelo site Databricks. Em vez disso, consulte O que é a lakehouse Federation?

O Databricks suporta a conexão com bancos de dados externos usando JDBC. Este artigo fornece a sintaxe básica para configurar e usar essas conexões, com exemplos em Python, SQL e Scala.

info

Experimental

As configurações descritas neste artigo são experimentais. Os recursos experimentais são fornecidos no estado em que se encontram e não recebem suporte do site Databricks por meio do suporte técnico ao cliente. Para obter suporte completo à federação de consultas, o senhor deve usar a lakehouse Federation, que permite que os usuários do Databricks aproveitem as ferramentas de sintaxe e governança de dados do Unity Catalog.

Partner Connect oferece integrações otimizadas para sincronizar dados com muitas fontes de dados externas. Consulte O que é o Databricks Partner Connect?

important

Os exemplos deste artigo não incluem nomes de usuário e senhas nos URLs JDBC. A Databricks recomenda o uso de segredos para armazenar suas credenciais de banco de dados. Por exemplo:

Python
username = dbutils.secrets.get(scope = "jdbc", key = "username")
password = dbutils.secrets.get(scope = "jdbc", key = "password")

Para fazer referência aos segredos de Databricks com SQL, o senhor deve configurar uma propriedade de configuração Spark durante a inicialização do clustering.

Para obter um exemplo completo de gerenciamento de segredos, consulte o tutorial: Criar e usar um segredo Databricks.

Estabeleça conectividade na nuvem

Databricks Os VPCs são configurados para permitir apenas o clustering Spark. Ao se conectar a outra infraestrutura, a prática recomendada é usar o peering VPC. Depois que o peering VPC for estabelecido, o senhor poderá verificar com o netcat utilidades no clustering.

Bash
%sh nc -vz <jdbcHostname> <jdbcPort>

Ler dados com JDBC

Você deve definir várias configurações para ler dados com JDBC. Observe que cada banco de dados usa um formato diferente para o <jdbc-url>.

Python
employees_table = (spark.read
.format("jdbc")
.option("url", "<jdbc-url>")
.option("dbtable", "<table-name>")
.option("user", "<username>")
.option("password", "<password>")
.load()
)

O Spark lê automaticamente o esquema da tabela do banco de dados e associa seus tipos aos tipos Spark SQL.

Python
employees_table.printSchema

Você pode executar consultas nesta tabela JDBC:

Python
display(employees_table.select("age", "salary").groupBy("age").avg("salary"))

Gravar dados com JDBC

Salvar dados em tabelas com JDBC utiliza configurações semelhantes à leitura. Veja o seguinte exemplo:

Python
(employees_table.write
.format("jdbc")
.option("url", "<jdbc-url>")
.option("dbtable", "<new-table-name>")
.option("user", "<username>")
.option("password", "<password>")
.save()
)

O comportamento padrão tenta criar uma nova tabela e gera um erro se uma tabela com esse nome já existir.

Você pode adicionar dados a uma tabela existente usando a seguinte sintaxe:

Python
(employees_table.write
.format("jdbc")
.option("url", "<jdbc-url>")
.option("dbtable", "<new-table-name>")
.option("user", "<username>")
.option("password", "<password>")
.mode("append")
.save()
)

Você pode sobrescrever uma tabela existente usando a seguinte sintaxe:

Python
(employees_table.write
.format("jdbc")
.option("url", "<jdbc-url>")
.option("dbtable", "<new-table-name>")
.option("user", "<username>")
.option("password", "<password>")
.mode("overwrite")
.save()
)

Controle o paralelismo para consultas JDBC

Por padrão, o driver JDBC consulta o banco de dados de origem com apenas um único encadeamento. Para melhorar o desempenho das leituras, você precisa especificar várias opções para controlar quantas consultas simultâneas o Databricks faz ao seu banco de dados. Para clusters pequenos, definir a opção numPartitions igual ao número de núcleos de executor no seu cluster garante que todos os nós consultem os dados em paralelo.

atenção

Definir numPartitions para um valor alto em um cluster grande pode resultar em desempenho negativo para o banco de dados remoto, pois muitas consultas simultâneas podem sobrecarregar o serviço. Isso é especialmente problemático para bancos de dados de aplicativos. Tenha cautela ao definir esse valor acima de 50.

nota

Acelere as consultas selecionando uma coluna com um índice calculado no banco de dados de origem para o partitionColumn.

O exemplo de código a seguir demonstra como configurar o paralelismo para um cluster com oito núcleos:

Python
employees_table = (spark.read
.format("jdbc")
.option("url", "<jdbc-url>")
.option("dbtable", "<table-name>")
.option("user", "<username>")
.option("password", "<password>")
# a column that can be used that has a uniformly distributed range of values that can be used for parallelization
.option("partitionColumn", "<partition-key>")
# lowest value to pull data for with the partitionColumn
.option("lowerBound", "<min-value>")
# max value to pull data for with the partitionColumn
.option("upperBound", "<max-value>")
# number of partitions to distribute the data into. Do not set this very large (~hundreds)
.option("numPartitions", 8)
.load()
)
nota

O Databricks suporta todas as opções do Apache Spark para configurar JDBC.

Ao gravar em bancos de dados usando JDBC, o Apache Spark usa o número de partições na memória para controlar o paralelismo. Você pode reparticionar os dados antes de gravar para controlar o paralelismo. Evite um número alto de partições em clusters grandes para não sobrecarregar seu banco de dados remoto. O exemplo a seguir demonstra como reparticionar em oito partições antes de gravar:

Python
(employees_table.repartition(8)
.write
.format("jdbc")
.option("url", "<jdbc-url>")
.option("dbtable", "<new-table-name>")
.option("user", "<username>")
.option("password", "<password>")
.save()
)

Enviar uma consulta para o mecanismo de banco de dados

Você pode transferir uma consulta inteira para o banco de dados e retornar apenas o resultado. O parâmetro table identifica a tabela JDBC a ser lida. Você pode usar qualquer coisa que seja válida em uma cláusula FROM de consulta SQL.

Python
pushdown_query = "(select * from employees where emp_no < 10008) as emp_alias"

employees_table = (spark.read
.format("jdbc")
.option("url", "<jdbc-url>")
.option("dbtable", pushdown_query)
.option("user", "<username>")
.option("password", "<password>")
.load()
)

Controle o número de linhas buscadas por consulta

Os drivers JDBC têm um parâmetro fetchSize que controla o número de linhas buscadas por vez no banco de dados remoto.

Contexto

Resultado

Muito baixo

Alta latência devido a muitas idas e vindas (poucas linhas retornadas por consulta).

Muito alto

Erro de falta de memória (muitos dados retornados em uma consulta)

O valor ideal depende da carga de trabalho. As considerações incluem:

  • Quantas colunas são retornadas pela consulta?
  • Quais tipos de dados são retornados?
  • Por quanto tempo as strings em cada coluna são retornadas?

Sistemas podem ter valores default muito pequenos e podem se beneficiar de ajustes. Por exemplo: o valor padrão de fetchSize no Oracle é 10. Aumentá-lo para 100 reduz o número total de consultas que precisam ser executadas em um fator de 10. Resultados JDBC são tráfego de rede, então evite números muito grandes, mas valores ideais podem estar na casa dos milhares para muitos conjuntos de dados.

Use a opção fetchSize como no exemplo a seguir:

Python
employees_table = (spark.read
.format("jdbc")
.option("url", "<jdbc-url>")
.option("dbtable", "<table-name>")
.option("user", "<username>")
.option("password", "<password>")
.option("fetchSize", "100")
.load()
)