Depuração de Database com IA no Databricks com PostgreSQL
1. Visão geral
Quando uma aplicação se conecta ao PostgreSQL no Databricks (via Lakebase ou Lakehouse Federation) encontra um erro, ler o stack trace, logs do HikariCP e EXPLAIN ANALYZE manualmente consome muito tempo. O Databricks tem um AI Assistant integrado que pode ler logs, consultas SQL e configurações de pool de conexão para sugerir causas raiz e formas de corrigir diretamente.
Este artigo explica como o mecanismo de depuração de banco de dados com IA funciona, depois passa por três cenários comuns de erro PostgreSQL (pool esgotado, query N+1, falta de permissão) com código Spring Boot para você reproduzir e verificar por conta própria as sugestões que a IA fornece. Ao final, você saberá como preparar logs e consultas para que a IA (ou você mesmo) faça diagnósticos mais rápidos e precisos.
2. Databricks Postgres (Lakebase) é o quê
Lakebase é um PostgreSQL gerenciado executado dentro do workspace do Databricks, usado para cargas de trabalho OLTP (transacionais) ao lado do Delta Lake para OLAP. Aplicações backend se conectam ao Lakebase da mesma forma que se conectariam a um PostgreSQL comum — via JDBC, com host/port/database fornecidos pelo Databricks.
2.1. Conectando a partir de Spring Boot
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
spring.datasource.url=jdbc:postgresql://<workspace>.lakebase.databricks.com:5432/orders_db
spring.datasource.username=app_user
spring.datasource.password=${DB_PASSWORD}
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.connection-timeout=3000
Esta é a configuração mínima: maximum-pool-size e connection-timeout são dois parâmetros que aparecerão continuamente nos casos de depuração na seção 4, pois a IA geralmente começa a análise a partir daqui.
3. Como a Depuração de Database com IA no Databricks funciona
3.1. Fontes de dados que a IA lê
O Databricks Assistant não “adivinha” aleatoriamente — ele lê três fontes:
- Stack trace / exception log de um job ou notebook.
- Plano de consulta (
EXPLAIN ANALYZE) quando você pergunta sobre uma consulta lenta. - Schema e metadados (tabelas, índices, restrições) para verificar a validade do SQL.
Em outras palavras, a IA só é boa quando seus logs têm detalhes suficientes. Uma exceção que apenas imprime "Connection is not available" dará sugestões muito vagas comparado a um log que inclui o tamanho do pool atual e o número de conexões ativas.
3.2. Fluxo de depuração típico
1. Você cola o stack trace ou a consulta SQL com erro no Databricks Assistant.
2. A IA identifica o tipo de erro: pool de conexão, sintaxe, permissão, bloqueio, timeout...
3. A IA compara com o schema/metadata existente no workspace.
4. A IA sugere correções: alterar config, corrigir SQL, adicionar índice, executar GRANT...
5. Você aplica a correção, executa novamente, a IA confirma que os logs estão limpos.
A próxima seção simula exatamente esse fluxo com três casos específicos.
4. Prática: Reproduzindo erros e lendo sugestões de depuração
4.1. Preparando dados
CREATE TABLE customers (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL
);
CREATE TABLE orders (
id BIGSERIAL PRIMARY KEY,
customer_id BIGINT REFERENCES customers(id),
total NUMERIC(12,2) NOT NULL,
created_at TIMESTAMP DEFAULT now()
);
E a entity correspondente:
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "customer_id")
private Customer customer;
private BigDecimal total;
}
4.2. Caso 1 — Pool de conexão esgotado
O serviço abaixo sofre de vazamento de conexão porque abre EntityManager manualmente sem fechá-lo:
@Service
public class OrderReportService {
@PersistenceContext
private EntityManager entityManager;
public List<Order> findAllOrdersUnsafe() {
EntityManager em = entityManager.getEntityManagerFactory()
.createEntityManager(); // nunca fecha()
return em.createQuery("SELECT o FROM Order o", Order.class)
.getResultList();
}
}
Chamar esta API continuamente gerará logs:
java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available,
request timed out after 3000ms.
Quando você fornece esse stack trace para a IA junto com o arquivo application.properties, as sugestões geralmente são:
- Pool size (10) não é a causa principal; o problema é que a conexão não está sendo devolvida ao pool.
- Revise os locais onde createEntityManager()/getConnection() é chamado manualmente.
- Certifique-se de usar try-with-resources ou deixar o Spring gerenciar a transação.
A correção correta é deixar de criar EntityManager manualmente e usar o repositório padrão:
public interface OrderRepository extends JpaRepository<Order, Long> {
List<Order> findAll();
}
@Service
public class OrderReportService {
private final OrderRepository orderRepository;
public OrderReportService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
public List<Order> findAllOrdersSafe() {
return orderRepository.findAll(); // Spring gerencia a conexão automaticamente
}
}
Observação: Aumentar
maximum-pool-sizequando encontrar esse erro é a direção errada — apenas adia o problema em vez de corrigir o vazamento de conexão real.
4.3. Caso 2 — Query N+1 deixando o sistema lento
public List<OrderSummary> summarize(List<Order> orders) {
return orders.stream()
.map(o -> new OrderSummary(o.getId(), o.getCustomer().getName())) // lazy load
.toList();
}
Como customer é FetchType.LAZY, cada elemento gera uma consulta separada para customers. Executar EXPLAIN ANALYZE nos logs do Databricks mostrará centenas de vezes:
SELECT * FROM customers WHERE id = $1;
A IA ao ler esse plano de consulta geralmente aponta:
- 200 consultas que repetem o mesmo padrão SELECT ... WHERE id = $1 em uma única requisição.
- Suspeita de N+1 devido ao lazy loading sem JOIN FETCH.
- Sugestão: use JOIN FETCH ou @EntityGraph para consolidar em 1 consulta.
Corrigir usando JPQL JOIN FETCH:
@Query("SELECT o FROM Order o JOIN FETCH o.customer")
List<Order> findAllWithCustomer();
Resultado: apenas uma consulta SELECT ... JOIN customers ... em vez de N+1 consultas separadas.
4.4. Caso 3 — Falta de permissão (permission denied)
SELECT * FROM orders WHERE total > 1000;
ERROR: permission denied for table orders
A IA compara os metadados de função no Databricks e retorna a sugestão GRANT apropriada:
GRANT SELECT ON orders TO app_user;
Observação: Sempre revise as sugestões GRANT antes de executar em produção — a IA não conhece suas políticas de segurança internas, apenas sabe a sintaxe necessária para a consulta funcionar. Não conceda permissões mais amplas do que o mínimo necessário (princípio do menor privilégio).
5. Escrevendo testes para confirmar correções
Depois de corrigir N+1 no caso 4.3, você precisa testar para garantir que não há regressão:
@DataJpaTest
class OrderRepositoryTest {
@Autowired
private OrderRepository orderRepository;
@Autowired
private TestEntityManager entityManager;
@Test
void shouldFetchOrdersWithCustomerInOneQuery() {
Customer customer = new Customer();
customer.setName("Nón Lá Dev");
entityManager.persist(customer);
Order order = new Order();
order.setCustomer(customer);
order.setTotal(new BigDecimal("150.00"));
entityManager.persist(order);
entityManager.flush();
List<Order> orders = orderRepository.findAllWithCustomer();
assertThat(orders)
.hasSize(1)
.first()
.extracting(o -> o.getCustomer().getName())
.isEqualTo("Nón Lá Dev");
}
}
Este teste não “conta o número de consultas” diretamente, mas combinado com as estatísticas do Hibernate (spring.jpa.properties.hibernate.generate_statistics=true), você pode registrar quantas consultas são executadas e verificar se é 1 — esse é exatamente o tipo de log que a IA usa para confirmar se a correção foi eficaz.
6. Monitoramento para uma depuração com IA mais eficaz
Para que a IA (ou seus colegas que lerem os logs depois) faça diagnósticos rápidos, use logs estruturados em vez de apenas e.printStackTrace():
@RestControllerAdvice
public class DatabaseExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(DatabaseExceptionHandler.class);
@ExceptionHandler(DataAccessException.class)
public ResponseEntity<String> handle(DataAccessException ex) {
log.error("db_error_type={}, sql_state={}, message={}",
ex.getClass().getSimpleName(),
extractSqlState(ex),
ex.getMostSpecificCause().getMessage());
return ResponseEntity.status(503).body("Database error, retry later");
}
private String extractSqlState(DataAccessException ex) {
if (ex.getCause() instanceof SQLException sqlEx) {
return sqlEx.getSQLState();
}
return "unknown";
}
}
Logs em formato chave-valor (db_error_type=, sql_state=) são muito mais fáceis de fazer parsing do que stack traces puros, e são a entrada ideal quando você cola no Databricks Assistant para perguntar ‘por que esse erro ocorreu’.
7. Quando NÃO deve usar depuração com IA
- Erros relacionados a dados sensíveis: não cole logs contendo dados reais de clientes no assistente de IA, mesmo que internos — mascare primeiro.
- Problemas de performance em nível de infraestrutura (disk I/O, latência de rede entre regiões): a IA pode ler o plano de consulta mas não consegue ver a infraestrutura física, facilitando sugestões incorretas (por exemplo, dizer ‘adicione um índice’ quando a causa é a rede).
- Erros transientes pontuais: se uma exceção ocorrer apenas uma vez devido a falhas de rede, debugar com IA consome mais tempo do que simplesmente fazer retry e continuar monitorando.
- Substitui code review: as sugestões de GRANT ou mudanças de pool size da IA precisam ser confirmadas por alguém com permissões de infraestrutura, não devem ser aplicadas automaticamente em produção.
8. Conclusão
A depuração de banco de dados com IA no Databricks é forte em ler rapidamente stack traces, planos de consulta e metadados para identificar causas raiz — vazamento de conexão, query N+1, falta de permissão são três casos muito comuns que este artigo reproduziu com Spring Boot e PostgreSQL. O valor real está em ter logs estruturados e escrever testes para confirmar correções, pois a IA é tão boa quanto a qualidade dos dados que você fornece. Sempre valide as sugestões — especialmente GRANT de permissões ou mudanças de infraestrutura — antes de aplicar ao seu sistema real.