Partilhar via


Introdução à Performance

O desempenho das bases de dados é um tema vasto e complexo, abrangendo uma pilha inteira de componentes: a base de dados, redes, o driver da base de dados e camadas de acesso a dados como o EF Core. Embora camadas de alto nível e O/RMs como o EF Core simplifiquem consideravelmente o desenvolvimento de aplicações e melhorem a manutenção, por vezes podem ser opacos, ocultando detalhes internos críticos de desempenho, como o SQL a ser executado. Esta secção procura fornecer uma visão geral de como alcançar um bom desempenho com o EF Core e como evitar armadilhas comuns que podem degradar o desempenho da aplicação.

Identificar gargalos e medir, medir, medir

Como sempre no desempenho, é importante não se precipitar na otimização sem dados que mostrem um problema; como disse o grande Donald Knuth, "A otimização prematura é a raiz de todo o mal". A secção de diagnóstico de desempenho discute várias formas de perceber onde a sua aplicação está a passar tempo na lógica da base de dados e como identificar áreas problemáticas específicas. Uma vez identificada uma consulta lenta, podem ser consideradas soluções: a sua base de dados está a faltar um índice? Deves experimentar outros padrões de consultas?

Faça sempre benchmarks do seu código e possíveis alternativas – a secção de diagnóstico de desempenho contém um benchmark de exemplo com o BenchmarkDotNet, que pode usar como modelo para os seus próprios benchmarks. Não presuma que benchmarks públicos gerais se aplicam tal como estão ao seu caso de uso específico; uma variedade de fatores, como a latência da base de dados, a complexidade das consultas e a quantidade real de dados nas suas tabelas, pode ter um efeito profundo na determinação da melhor solução. Por exemplo, muitos benchmarks públicos são realizados em condições ideais de rede, onde a latência para a base de dados é quase nula, e com consultas extremamente leves que dificilmente requerem processamento (ou E/S de disco) do lado da base de dados. Embora estes sejam valiosos para comparar os overheads em tempo de execução de diferentes camadas de acesso a dados, as diferenças que revelam geralmente revelam-se negligenciáveis numa aplicação do mundo real, onde a base de dados realiza trabalho real e a latência em relação à base de dados é um fator de desempenho significativo.

Aspetos do desempenho do acesso a dados

O desempenho global do acesso a dados pode ser dividido nas seguintes categorias gerais:

  • Desempenho puro na base de dados. Com base de dados relacional, o EF traduz as consultas LINQ da aplicação nas instruções SQL executadas pela base de dados; estas próprias instruções SQL podem correr de forma mais ou menos eficiente. O índice certo no sítio certo pode fazer uma enorme diferença no desempenho do SQL, ou reescrever a sua consulta LINQ pode fazer com que o EF gere uma consulta SQL melhor.
  • Transferência de dados de rede. Como em qualquer sistema de rede, é importante limitar a quantidade de dados que circulam pela linha. Isto cobre garantir que só envia e carrega os dados que realmente vai precisar, mas também evitar o chamado efeito de "explosão cartesiana" ao carregar entidades relacionadas.
  • Viagens de ida e volta em rede. Para além da quantidade de dados que vão e vem, as viagens de ida e volta em rede, já que o tempo que uma consulta demora a executar na base de dados pode ser ofuscado pelos pacotes temporais que viajam entre a sua aplicação e a sua base de dados. A sobrecarga de ida e volta depende muito do ambiente; Quanto mais longe estiver o teu servidor de base de dados, maior a latência e mais caro é cada ida e volta. Com o advento da cloud, as aplicações encontram-se cada vez mais afastadas da base de dados, e aplicações "faladoras" que fazem demasiadas viagens de ida e volta apresentam desempenho degradado. Por isso, é importante perceber exatamente quando a sua aplicação contacta a base de dados, quantas viagens de ida e volta realiza e se esse número pode ser minimizado.
  • Sobrecarga de tempo de execução EF. Finalmente, o próprio EF acrescenta algum overhead de execução às operações da base de dados: o EF precisa de compilar as suas consultas do LINQ para SQL (embora isso normalmente deva ser feito apenas uma vez), o acompanhamento de alterações adiciona algum overhead (mas pode ser desativado), etc. Na prática, a sobrecarga de EF para aplicações do mundo real é provavelmente negligenciável na maioria dos casos, pois o tempo de execução da consulta na base de dados e a latência da rede dominam o tempo total; Mas é importante perceber quais são as tuas opções e como evitar algumas armadilhas.

Sabe o que se passa por trás do capot

O EF permite aos programadores concentrar-se na lógica de negócio ao gerar SQL, materializar resultados e realizar outras tarefas. Como qualquer camada ou abstração, também tende a esconder o que está a acontecer por baixo, como as consultas SQL reais a serem executadas. O desempenho não é necessariamente um aspeto crítico de todas as aplicações, mas em aplicações onde existe, é vital que o programador compreenda o que o EF está a fazer por elas: inspecionar consultas SQL de saída, fazer idas e voltas para garantir que o problema N+1 não está a ocorrer, etc.

Cache fora da base de dados

Finalmente, a forma mais eficiente de interagir com uma base de dados é não interagir com ela de todo. Por outras palavras, se o acesso à base de dados aparecer como um gargalo de desempenho na sua aplicação, pode valer a pena armazenar em cache certos resultados fora da base de dados, para minimizar pedidos. Embora a cache adicione complexidade, é uma parte especialmente crucial de qualquer aplicação escalável: enquanto a camada de aplicação pode ser facilmente escalada adicionando servidores adicionais para lidar com o aumento da carga, escalar a camada da base de dados é geralmente muito mais complicado.