Join vs. Subqueries no MySQL

Trabalhar com bases de dados gigantes nunca é uma tarefa das mais simples. Facilidades de ORM caem por terra, em geral, por questões de desempenho. Jobs diários de migração, integração ou data mining acabam virando uma tarefa demorada e de processamento caro, então fazer tuning de SQL para estes jobs é algo que pode – e deve – ser feito para aumentar a performance.

Dentre as dezenas de tarefas para aumento de performance, estão a ordenação correta das tabelas na hora de fazer as operações de junção. Em geral, joins usando chaves ou campos indexados são mais rápidos que subqueries. Mas para minha surpresa, descobri essa semana que no MySQL isso não é de todo verdade.

A questão é que, usando o comando EXPLAIN EXTENDED e analisando os planos de execução gerados pela engine do MySQL, descobri que o MySQL implementa uma forma interessante de uso de subqueries: quando a quantidade de colunas envolvidas na junção é maior que a quantidade de colunas envolvidas no filtro da subquery, a subquery é mais rápida. O motivo: o MySQL executa esta subquery ANTES das seleções mais externas e mantém o que é possível em cache. Ou seja, exceto os filtros, o arcabouço do resultset que vai ser utilizado como filtro (um in, por exemplo) já está feito, o que resulta em um aumento de performance de no mínimo 50%. Considerando que parte dos filtros pode também sofrer agrupamento, esse ganho pode ser ainda maior. E mais: como seu filtro é mais restritivo logo no começo, o tamanho da sua seleção mais externa tende a ser num universo de dados muito menor. No meu caso, o ganho total foi de mais de 80%.

Portanto, ao fazer SQL Tuning com MySQL, não saia jogando toda e qualquer subquery pra cima e trocando por um Join; talvez o processo contrário seja ainda mais indicado pra você.

Escolhendo a ferramenta de Integração Contínua

Há diversas opções de ferramentas de integração contínua à sua disposição. Decidir qual delas é a adequada pra você é uma questão de conhecer o(s) seu(s) projeto(s) e suas necessidades dentro dele(s). Há diversos comparativos por aí, com tabelas e tudo mais. Você já é bem grandinho e pode decidir por você mesmo. Entretanto, há aqueles que já são “padrão de mercado” e outros que estão no ostracismo (geralmente eles merecem estar lá); então eu vou citar alguns dos CIT padrões por aqui e mostrar as principais características deles, o que pode facilitar um pouco o processo de decisão.

Apache Continuum
Desenvolvido pela Apache (jura?), ele roda num Servlet Container qualquer, como o Tomcat. Ele baixa o código alterado do controle de versão (SVN, CVS, VSS, Mercurial e mais uma pilha deles), roda o build, distribui no servidor de aplicação (ou servlet container) e roda os testes unitários. Se o build quebrar, manda e-mail pra quem quebrou o build e pra quem mais estiver interessado no processo. A interface dele não é das melhores, mas a configuração inicial é simples de dar dó: aponte para o seu pom.xml e ele faz o resto. Mas é aí que mora a encrenca: se você não usa o Maven, adeus Continuum. “Ah, mas eu uso o Ant”. Sorry, você vai ter que criar uma etapa a mais no seu processo de build só pra poder usá-lo. Então, se você é como eu, que quer distância do Maven, o Continuum não é uma escolha viável. Além disso, eu sou do tipo que gosta de usar a IDE pra controlar as coisas, e o Continuum não se integra nem com Eclipse, nem com Netbeans.

Team Foundation Server
Esse é filho da Microsoft. Proprietário e pago. Se integra muito bem com o Visual Studio, por motivos óbvios. A principal diferença entre ele e as outras ferramentas é que o TFS já é o kit todo: o controle de versão, o servidor de integração contínua e um project tracker. E claro, roda em Windows. Se você usa Linux, já tem controle de versão, não usa o Visual Studio e, como eu, prefere trabalhar com ferramentas Open Source, o TFS não é pra você – e nem pra mim.

CruiseControl
Nota importante: não o confunda com o CruiseControl.rb. Eles não têm (mais) absolutamente nenhuma relação além do nome (bem) parecido. A parte boa dele é o dashboard, que te dá bastante informação sobre os builds, e tem plugin pra quase tudo que você imaginar, inclusive integração com o Eclipse e envio de e-mails. Ele não está descontinuado, mas o movimento anda bem fraco no projeto. E pra jogar na vala de vez a minha vontade de usá-lo, é uma aplicação standalone, o que o torna proibitivo em alguns ambientes.

CruiseControl.rb
Esse é filho da ThoughtWorks, tal qual o CruiseControl; as semelhanças terminam aí. Se integra com todos – sim, todos – os providers de controle de versão, mas ele é especialmente moldado para o trabalho com o Git. Se você trabalha com SVN ou CVS, funciona, mas a configuração não é das mais triviais. Dá um trabalho danado colocar esse cara pra rodar, especialmente por causa das milhões de dependências do Ruby. E convenhamos: se seu projeto não é Ruby, vai instalar isso tudo no seu servidor a troco de que? Por uma só ferramenta, e que pode ser facilmente substituída por outra? Eu sou contra. Se meu ambiente já é todo Java, não vou entupir mais ainda o meu VPS, que já é pobrezinho.

Hudson
Esse é o queridinho da galera. Quando a Oracle comprou a Sun, a Oracle reclamou os direitos do nome e queria continuar o desenvolvimento como produto. Sem se alongar muito: a comunidade fez um fork dele e batizou de Jenkins, do qual vou falar mais abaixo. Com isso, o Hudson hoje continua Open Source, e tem suporte da própria Oracle. As funcionalidades dele são praticamente as mesmas do Jenkins, por motivos óbvios, mas essa questão de suporte da Oracle pode ser um ponto relevante na minha escolha. Na minha, não é – até porquê o suporte da Oracle é uma piada pro Hudson: não saiu nada de novo desde Dezembro / 2010.

Jenkins
Se o Hudson é o queridinho da galera, o Jenkins é o queridinho da galera E da galera mais xiita do Open Source, já que esse tem suporte e é provido pela comunidade diretamente. A interface é igual, as funcionalidades são quase todas iguais, mas o projeto é bem mais movimentado que o Hudson: desde o split (ou fork, como queira), ele já ganhou uma coleção consideravelmente grande de plugins e novas features. Se integra com Git, SVN, CVS, Maven, Ant, etc. mas, ao contrário dos outros, ao contrário do controle de versão, NADA nele é obrigatório na configuração. Você usa o que bem entender. Roda num Servlet Container, o que facilita no caso de você já ter um servidor de aplicação rodando num servidor de testes, por exemplo. Mas se você não tiver, tudo bem: ele tem uma versão “executável”, que não é standalone, mas que faz o serviço de auto-deploy dele mesmo pra você. Configurado o repositório do controle de versão para o seu projeto, está feito: é só executar os builds pelo dashboard, que te dá as informações resumidas do build e acesso ao console. Executa os testes unitários, inclusive integrados ao Selenium e outras ferramentas de testes de aceitação. Deu erro? Envia e-mail e até SMS. Eu chamo ele carinhosamente de “Integração Contínua para Chimpanzés”. E você pode agendar os builds para serem executados automaticamente, usando cron. Se você não sabe usar cron, larga esse teclado e deixa um administrador de verdade mexer aí. Ou pesquisa, também serve.

Minha escolha, baseada nos fatos acima, foi pelo Jenkins. Eu não sou (nem um pouco) xiita de Open-Source, mas ele é de longe a ferramenta mais fácil de colocar em pleno funcionamento. Além disso, os últimos plugins e correção de bugs pela comunidade são bastante relevantes pra mim (como a integração o Pentaho).

Mas e pra colocar o Jenkins pra funcionar? Daí é outra história… conto depois 😉