Pergunta

Então, eu tenho vindo a construir Django aplicações por um tempo agora, e beber o cool-ajuda e de tudo:. Usando apenas o ORM e nunca escrever SQL personalizada

A página principal do site (a principal interface onde os usuários vão gastar 80% - 90% do seu tempo) estava ficando lento uma vez que você tem uma grande quantidade de conteúdo específico do usuário (ou seja, fotos, amigos, outros dados, etc)

Então, eu apareci na logger sql (foi pré-instalado com pinax, eu só permitiu-nos ajustes) e imagine minha surpresa quando ele relatou sobre 500 banco de dados consultas !! Com a mão codificado sql Eu quase nunca correu mais de 50 nas páginas mais complexas.

Em retrospectiva, não é todos juntos surpreendente, mas parece que isso não pode ser bom.

... mesmo que apenas uma dúzia ou mais das consultas tomar 1ms +

Então, eu estou pensando, Quanto sobrecarga é lá em uma viagem de volta para mysql ? Django e mysql estão em execução no mesmo servidor assim não deve haver qualquer sobrecarga relacionado rede.

Foi útil?

Solução

Existem algumas maneiras de reduzir o volume de consultas.

  1. Use .filter() e .all() para obter um monte de coisas; escolher em função do ponto de vista (ou molde através {%if%}). Python pode processar um lote de linhas mais rápido do que o MySQL.

    "Mas eu poderia enviar demais para o modelo". É verdade, mas você vai executar menos solicitações SQL. Medir para ver o que é melhor.

    Isto é o que você costumava fazer quando você escreveu SQL. Não é errado - não quebrar o ORM -. Mas otimiza o trabalho e coloca DB subjacente ao processamento para a função de vista e o modelo

  2. navegação consulta Evite no modelo. Quando você faz {{foo.bar.baz.quux}}, SQL é usado para obter o bar associado com foo, então o baz associado ao bar, então o quux associado com baz. Você pode ser capaz de reduzir este negócio consulta com algum .filter() cuidadosa e processamento Python para montar uma tupla útil na função de visualização.

    Novamente, isso era algo que você costumava fazer quando SQL artesanais. Neste caso, você recolhe lotes maiores de objetos gerenciados pelo ORM na função de visualização e fazer sua filtragem em Python em vez de através de um monte de pedidos ORM individuais.

    Esta não quebra o ORM. Ele muda o perfil de uso de lotes de pequenas consultas para algumas consultas maiores.

Outras dicas

Apenas porque você está usando um ORM não significa que você não deve fazer ajuste de desempenho.

Eu tive - como você - uma home page de uma das minhas aplicações que tiveram baixo desempenho. Vi que eu estava fazendo centenas de consultas para exibir essa página. Eu fui olhando para o meu código e percebeu que, com algum uso cuidadoso de select_related() minhas consultas traria mais dos dados que eu precisava -. Eu fui de centenas de consultas para dezenas

Você também pode executar um profiler do SQL e veja se não há índices que ajudariam suas perguntas mais frequentes -. Você sabe, coisas de banco de dados padrão

O cache é também seu amigo, eu acho. Se um lote de uma página não está mudando, você precisa consultar o banco de dados de cada vez?

Se tudo isso falhar, lembre-se: o ORM é grande, e sim - você deve tentar usá-lo porque é a filosofia Django; , mas você não está casada com ele .

Se você realmente tem um usecase onde estudar e ajustar a navegação ORM não ajuda, se você tem certeza que você poderia fazê-lo muito melhor com uma consulta padrão:. Usar SQL puro para esse caso

A sobrecarga de cada consultas é apenas uma parte da imagem. O tempo de ida e volta real entre os servidores do Django e MySQL é provavelmente muito pequena já que a maioria de suas consultas estão voltando em menos de um milissegundo. O maior problema é que o número de consultas emitidas para seu banco de dados pode sobrecarregar-lo rapidamente. 500 consultas para uma página é forma de muito, mesmo 50 parece muito para mim. Se os usuários dez visualizar complicado páginas você está agora até 5000 consultas.

O tempo de ida e volta para o servidor de banco de dados é mais um fator quando o chamador está acessando o banco de dados a partir de uma Wide Area Network, onde roundtrips pode facilmente ser entre 20ms e 100ms.

Eu definitivamente olhar em usar algum tipo de cache.

Há sempre sobrecarga em chamadas de banco de dados, no seu caso a sobrecarga não é que ruim, porque a aplicação e banco de dados estão na mesma máquina para que não haja latência da rede, mas ainda há um custo significativo .

Quando você faz um pedido ao banco de dados que tem de se preparar para serviço essa solicitação fazendo uma série de coisas, incluindo:

  • alocação de recursos (buffers de memória, tabelas temporárias etc) para a conexão do servidor de banco de dados / thread que irá lidar com o pedido,
  • De-serialização o sql e parâmetros (isto é necessário, mesmo em uma máquina como esta é uma solicitação de inter-processo, a menos que você estiver usando um banco de dados embeded)
  • Verificar se a consulta existe no cache de consultas se não otimizá-lo e colocá-lo no cache.
    • Note também que se as consultas não são parametrizado (isto é, os valores não são separados do SQL) isso pode resultar em perdas de cache para instruções que devem ser o mesmo significado que cada solicitação resultados da consulta que está sendo analisado e aperfeiçoado cada tempo.
  • processar a consulta.
  • Preparar e retornar os resultados para o cliente.

Esta é apenas uma visão geral dos tipos de coisas a maioria dos sistemas de gerenciamento de banco de dados fazer para processar um pedido de SQL. Você incorrer essa sobrecarga 500 vezes, mesmo se a consulta em si é executado de forma relativamente rápida. interações de banco de dados linha de fundo até a base de dados local não são tão barato quanto se poderia esperar.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top