Ao trabalhar com InterSystems IRIS, desenvolvedores e arquitetos de banco de dados frequentemente enfrentam uma decisão crítica: usar Dynamic SQL ou Embedded SQL para consultar e atualizar dados. Ambos os métodos têm seus pontos fortes e casos de uso únicos, mas entender suas implicações de desempenho é essencial para fazer a escolha certa. O tempo de resposta, uma métrica chave na avaliação do desempenho de aplicações, pode variar significativamente dependendo da abordagem SQL utilizada. Dynamic SQL oferece flexibilidade, pois as consultas podem ser construídas e executadas em tempo de execução, tornando-o ideal para cenários com necessidades de consulta imprevisíveis ou altamente variáveis. Por outro lado, Embedded SQL enfatiza a estabilidade e a eficiência ao integrar código SQL diretamente na lógica da aplicação, oferecendo tempos de resposta otimizados para padrões de consulta predefinidos.
Neste artigo, explorarei os tempos de resposta ao usar esses dois tipos de SQL e como eles dependem de diferentes estruturas de classe e do uso de parâmetros. Para fazer isso, usarei as seguintes classes do diagrama:
Para testar os tempos, criei o seguinte número de objetos para cada classe:
- Paciente - 50 milhões
- Visita - 150 milhões
- Médico - 500 mil
- Endereço - 50 milhões
Dessa forma, esperava ver um tempo razoável para executar as consultas e observar as diferenças entre a execução de Embedded SQL e Dynamic SQL. O único índice que adicionei foi o índice automático de um-para-muitos para o relacionamento Médico-Visita.
Então, vamos dar uma olhada nas consultas que vou executar e, em seguida, na duração da execução:
select count(*) from Hospital.Address select count(*) from Hospital.Address where State = :param select count(*) from Hospital.Patient p left join Hospital.Address a on p.address = a.id select count(*) from Hospital.Patient p left join Hospital.Address a on p.address = a.id where a.State = :param select count(a.Address->State) from Hospital.Patient a select count(*) from Hospital.Patient p where p.Address->State = :param select count(p.Visit->VisitDate) from Hospital.Patient p select count(*) from Hospital.Patient p where p.Visit->VisitDate > :param select count(v.Patient->Name) from Hospital.Visit v select count(*) from Hospital.Visit v where v.Patient->Name %startswith :param select count(v.Patient->Address->State) from Hospital.Visit v select count(*) from Hospital.Visit v where v.Patient->Address->State = :param select count(v.Doctor->Name) from Hospital.Visit v select count(*) from Hospital.Visit v where v.Doctor->Name %startswith :param select count(*) into :p from Hospital.Visit v where v.Doctor->Name %startswith :param and v.Patient->Name %startswith :param select count(*) into :p from Hospital.Visit v where v.Doctor->Name %startswith :param and v.Patient->Name %startswith :param and v.Patient->Address->State = :param1
Obviamente, o código acima é a sintaxe para Embedded SQL (porque há parâmetros nomeados). Para Dynamic SQL, as consultas são quase as mesmas, mas em vez de parâmetros nomeados, tenho parâmetros não nomeados 😉. Por exemplo, para a última, tenho a seguinte consulta:
select count(*) from Hospital.Visit v where v.Doctor->Name %startswith ? and v.Patient->Name %startswith ? and v.Patient->Address->State = ?
Agora, vamos dar uma olhada nos resultados:
No of query | Embedded SQL (sec) | Dynamic SQL (sec) |
1 | 49 | 12 |
2 | 3 | 3 |
3 | 32 | 26 |
4 | 47 | 46 |
5 | 48 | 46 |
6 | 47 | 46 |
7 | ||
8 | ||
9 | 31 | 26 |
10 | 83 | 81 |
11 | 41 | 45 |
12 | 73 | 71 |
13 | 23 | 26 |
14 | 1 | 1 |
15 | 2 | 2 |
16 | 3 | 3 |
Podemos observar um valor discrepante colossal, que é a primeira consulta. O Embedded SQL levou muito mais tempo para executar do que o Dynamic SQL. Executar as mesmas consultas várias vezes me deu resultados mais ou menos iguais. Então, é o que é.
Em geral, podemos ver que o relacionamento pai-filho é muito mais lento do lado da propriedade dos filhos, mesmo que todos os dados de Paciente e Visita estejam armazenados no global de Paciente. O índice salvou o dia para o relacionamento de um-para-muitos, e o tempo de execução foi consideravelmente menor. No geral, o tempo de resposta é quase sempre similar e difere em menos de 10%; às vezes, é o mesmo. Claro, usei consultas simples que não demoraram muito para preparar, então essa etapa pôde ser quase ignorada.