{"id":21331,"date":"2026-09-12T15:01:49","date_gmt":"2026-09-12T13:01:49","guid":{"rendered":"https:\/\/webhosting.de\/mariadb-optimizer-trace-sql-performance-analyse-datenbank\/"},"modified":"2026-09-12T15:01:49","modified_gmt":"2026-09-12T13:01:49","slug":"mariadb-otimizador-rastreio-analise-de-desempenho-sql-base-de-dados","status":"publish","type":"post","link":"https:\/\/webhosting.de\/pt\/mariadb-optimizer-trace-sql-performance-analyse-datenbank\/","title":{"rendered":"Rastreio do Otimizador do MariaDB \u2013 Compreender as consultas SQL em pormenor"},"content":{"rendered":"<p>Com o \u00aboptimizer trace\u00bb no MariaDB, consigo compreender, passo a passo, por que raz\u00e3o o otimizador escolhe um determinado plano e quais as variantes que rejeita. Este registo JSON mostra-me <strong>Decis\u00f5es<\/strong> sobre custos, ordens de jun\u00e7\u00e3o e filtros, para que eu possa adaptar as consultas SQL de forma espec\u00edfica.<\/p>\n\n<h2>Pontos centrais<\/h2>\n\n<ul>\n  <li><strong>Transpar\u00eancia<\/strong>: Um registo baseado em JSON explica as reescritas, os custos e os planos rejeitados.<\/li>\n  <li><strong>Foco<\/strong>: as fun\u00e7\u00f5es `join_preparation` e `join_optimization` fornecem as informa\u00e7\u00f5es mais importantes.<\/li>\n  <li><strong>Sistema de controlo<\/strong>: As vari\u00e1veis de sess\u00e3o limitam a sobrecarga e a mem\u00f3ria.<\/li>\n  <li><strong>Fluxo de trabalho<\/strong>: EXPLAIN\/ANALYZE para o plano, Trace para o \u201eporqu\u00ea\u201c.<\/li>\n  <li><strong>Vantagens pr\u00e1ticas<\/strong>: Ajustar de forma fundamentada os \u00edndices, as estat\u00edsticas e as ordens de jun\u00e7\u00e3o.<\/li>\n<\/ul>\n\n\n<figure class=\"wp-block-image size-full is-resized\">\n  <img fetchpriority=\"high\" decoding=\"async\" src=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/09\/mariadb-optimizer-trace-0294.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>O que \u00e9 o MariaDB Optimizer Trace?<\/h2>\n\n<p>Desde a vers\u00e3o 10.4 que o MariaDB implementa um <strong>Optimizador<\/strong> Trace, que documenta em formato JSON cada fase de otimiza\u00e7\u00e3o mais significativa de uma instru\u00e7\u00e3o SELECT, UPDATE ou DELETE. Nele, consigo ver como o motor expande as consultas, normaliza as condi\u00e7\u00f5es e, por fim, determina a ordem das jun\u00e7\u00f5es, incluindo os acessos aos \u00edndices. Esta vis\u00e3o \u00e9 significativamente mais aprofundada do que o EXPLAIN, que mostra principalmente o plano final, e revela alternativas rejeitadas com as respetivas justifica\u00e7\u00f5es. O rastreio fica na mem\u00f3ria por cada liga\u00e7\u00e3o e est\u00e1 dispon\u00edvel atrav\u00e9s de <code>information_schema.OPTIMIZER_TRACE<\/code> pronto. Assim, obtenho uma explica\u00e7\u00e3o completa e leg\u00edvel por m\u00e1quina sobre o <strong>Passos<\/strong>, que conduziram a um plano de execu\u00e7\u00e3o.<\/p>\n\n<h2>Ativar e ler o Optimizer Trace<\/h2>\n\n<p>Ativo a fun\u00e7\u00e3o especificamente por sess\u00e3o, para poder realizar diagn\u00f3sticos sem sobrecarga global e ter controlo total sobre <strong>Mem\u00f3ria<\/strong> tenho. Normalmente, utilizo <code>SET SESSION optimizer_trace = 'enabled=on';<\/code> e, se necess\u00e1rio <code>SET SESSION optimizer_trace_max_mem_size = 1048576;<\/code> ou superior, se o rastreio for extenso. Depois, executo a consulta suspeita e leio o rastreio com <code>SELECT * FROM information_schema.OPTIMIZER_TRACE LIMIT 1\\G;<\/code>. Importante: a tabela guarda apenas a \u00faltima consulta da liga\u00e7\u00e3o ativa, e tenho em conta campos como <code>MISSING_BYTES_BEYOND_MAX_MEM_SIZE<\/code> ou <code>INSUFFICIENT_PRIVILEGES<\/code> para obter indica\u00e7\u00f5es de diagn\u00f3stico. Esta forma de trabalhar mant\u00e9m o ambiente de produ\u00e7\u00e3o simplificado e facilita a an\u00e1lise <strong>exato<\/strong>.<\/p>\n\n<table>\n  <thead>\n    <tr>\n      <th>Vari\u00e1vel\/Campo<\/th>\n      <th>Objetivo<\/th>\n      <th>Exemplo de valor<\/th>\n    <\/tr>\n  <\/thead>\n  <tbody>\n    <tr>\n      <td><code>optimizer_trace<\/code><\/td>\n      <td>Ativa o registo por sess\u00e3o<\/td>\n      <td><code>'enabled=on'<\/code><\/td>\n    <\/tr>\n    <tr>\n      <td><code>optimizer_trace_max_mem_size<\/code><\/td>\n      <td>Capacidade m\u00e1xima de armazenamento por trace<\/td>\n      <td><code>1048576<\/code> (1 MB)<\/td>\n    <\/tr>\n    <tr>\n      <td><code>OPTIMIZER_TRACE.QUERY<\/code><\/td>\n      <td>Instru\u00e7\u00e3o SQL original<\/td>\n      <td><code>SELECT ...<\/code><\/td>\n    <\/tr>\n    <tr>\n      <td><code>OPTIMIZER_TRACE.TRACE<\/code><\/td>\n      <td>Documento JSON da otimiza\u00e7\u00e3o<\/td>\n      <td>Texto JSON<\/td>\n    <\/tr>\n    <tr>\n      <td><code>MISSING_BYTES_BEYOND_MAX_MEM_SIZE<\/code><\/td>\n      <td>Bytes cortados quando o trace \u00e9 demasiado grande<\/td>\n      <td>0 ou quantidade<\/td>\n    <\/tr>\n    <tr>\n      <td><code>INSUFFICIENT_PRIVILEGES<\/code><\/td>\n      <td>A autoriza\u00e7\u00e3o de leitura \u00e9 suficiente?<\/td>\n      <td>0 ou 1<\/td>\n    <\/tr>\n  <\/tbody>\n<\/table>\n\n\n<figure class=\"wp-block-image size-full is-resized\">\n  <img decoding=\"async\" src=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/09\/mariadb_optimizer_besprechung_5829.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>Estrutura JSON: join_preparation e join_optimization<\/h2>\n\n<p>A estrutura JSON divide-se nos seguintes blocos <code>prepara\u00e7\u00e3o_de_jun\u00e7\u00e3o<\/code> e <code>otimiza\u00e7\u00e3o de jun\u00e7\u00f5es<\/code>, que s\u00e3o as primeiras que consulto, porque s\u00e3o as mais importantes <strong>Notas<\/strong> fornecer. Na sec\u00e7\u00e3o <code>prepara\u00e7\u00e3o_de_jun\u00e7\u00e3o<\/code> reconhe\u00e7o a consulta alargada (<code>expanded_query<\/code>) e vejo se e como o motor transformou as condi\u00e7\u00f5es ou as proje\u00e7\u00f5es. O segundo bloco <code>otimiza\u00e7\u00e3o de jun\u00e7\u00f5es<\/code> regista estimativas de linhas, planos analisados, a ordem de jun\u00e7\u00e3o selecionada e a adi\u00e7\u00e3o de partes seletivas da condi\u00e7\u00e3o WHERE \u00e0s tabelas. Os sub\u00e1rvores s\u00e3o particularmente \u00fateis <code>rows_estimation<\/code>, <code>planos_de_execu\u00e7\u00e3o_considerados<\/code> e <code>atribuir_condi\u00e7\u00f5es_a_tabelas<\/code>, porque remetem diretamente para os pressupostos de custos e para as posi\u00e7\u00f5es dos filtros. Desta forma, consigo identificar rapidamente onde existem avalia\u00e7\u00f5es erradas ou situa\u00e7\u00f5es desfavor\u00e1veis <strong>\u00cdndices<\/strong> levam a planos que n\u00e3o s\u00e3o os melhores poss\u00edveis.<\/p>\n\n<h2>Compara\u00e7\u00e3o com EXPLAIN e ANALYZE<\/h2>\n\n<p>Para uma avalia\u00e7\u00e3o completa, combino o EXPLAIN, o ANALYZE e o <strong>Tra\u00e7o<\/strong> num procedimento fixo. Primeiro, utilizo <code>EXPLICAR<\/code> ou <code>EXPLAIN FORMAT=JSON<\/code>, para ver o plano selecionado e os percursos-chave. Depois, defino <code>EXPLAIN ANALYZE<\/code> para obter dados reais sobre o tempo de execu\u00e7\u00e3o e valores de contagem, como loops e linhas filtradas. Se ainda houver d\u00favidas, ativo o Optimizer Trace e verifico quais variantes o Optimizer analisou e rejeitou. Este artigo oferece-me uma introdu\u00e7\u00e3o sucinta \u00e0 interpreta\u00e7\u00e3o de <a href=\"https:\/\/webhosting.de\/pt\/interpretar-consultas-mysql-explain-e-analyze-otimizacao-de-consultas\/\">Compreender o EXPLAIN ANALYZE<\/a>, ao qual recorro como complemento, se necess\u00e1rio.<\/p>\n\n<h2>Compreender as decis\u00f5es de planeamento: custos, cardinalidades, filtros<\/h2>\n\n<p>A l\u00f3gica de decis\u00e3o baseia-se em cardinalidades, modelos de custos e na localiza\u00e7\u00e3o de <strong>Filtro<\/strong> ao longo do plano. No Trace, vejo, para cada ordem de jun\u00e7\u00e3o analisada, quais os conjuntos de linhas que o motor espera e como calcula a partir da\u00ed o custo total. Verifico se estat\u00edsticas desatualizadas ou correla\u00e7\u00f5es desfavor\u00e1veis levam a que as varreduras de intervalo sejam subestimadas e as varreduras completas sejam preferidas. Al\u00e9m disso, verifico se o motor aplica as condi\u00e7\u00f5es WHERE \u00e0 tabela mais seletiva com anteced\u00eancia suficiente, de modo a reduzir etapas de jun\u00e7\u00e3o dispendiosas. Desta forma, consigo chegar a conclus\u00f5es s\u00f3lidas sobre o motivo pelo qual um plano foi escolhido e como posso melhor\u00e1-lo com <strong>\u00cdndices<\/strong>, reescritas ou atualiza\u00e7\u00e3o de estat\u00edsticas.<\/p>\n\n\n<figure class=\"wp-block-image size-full is-resized\">\n  <img decoding=\"async\" src=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/09\/mariadb-optimizer-trace-sql-4271.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>Exemplo pr\u00e1tico: Rastreio de uma consulta de filtro simples<\/h2>\n\n<p>Em <code>SELECT * FROM t1 WHERE a &lt; 10<\/code> verifico em <code>prepara\u00e7\u00e3o_de_jun\u00e7\u00e3o<\/code>, se o motor ampliou a proje\u00e7\u00e3o e, eventualmente, consolidou condi\u00e7\u00f5es, o que me deu uma primeira <strong>Indicadores<\/strong> apresenta. Depois disso, vejo no bloco <code>rows_estimation<\/code>, quantas linhas o motor utiliza para o Range-Scan em <code>a<\/code> em compara\u00e7\u00e3o com o Full-Table-Scan. Se forem encontrados valores irrealistas, interpreto isso frequentemente como um sinal de estat\u00edsticas desatualizadas ou da falta de histogramas. Na sec\u00e7\u00e3o <code>planos_de_execu\u00e7\u00e3o_considerados<\/code> Percebo, em seguida, se o acesso ao \u00edndice foi realmente mais econ\u00f3mico do que a an\u00e1lise completa. Por fim, mostra <code>atribuir_condi\u00e7\u00f5es_a_tabelas<\/code>, se a condi\u00e7\u00e3o seletiva se aplica a <code>a<\/code> come\u00e7a a surtir efeito mais cedo do que previsto, o que reduz significativamente o tempo de execu\u00e7\u00e3o <strong>baixa<\/strong>.<\/p>\n\n<h2>Fun\u00e7\u00f5es JSON: extrair trechos espec\u00edficos<\/h2>\n\n<p>Como o trace est\u00e1 no formato JSON, filtro especificamente sub\u00e1rvores com <code>JSON_EXTRACT<\/code> e crio pequenas an\u00e1lises para dados recorrentes <strong>Amostra<\/strong>. Por exemplo, analiso apenas a lista dos planos considerados para verificar se determinadas sequ\u00eancias de jun\u00e7\u00f5es falham sistematicamente. Da mesma forma, extraio os campos de custos dos principais candidatos e comparo-os com os dados do ANALYZE, para detetar suposi\u00e7\u00f5es erradas. Atrav\u00e9s de vistas simples ou procedimentos armazenados, automatizo estas verifica\u00e7\u00f5es para as minhas sess\u00f5es de diagn\u00f3stico. Desta forma, construo uma ferramenta leve <strong>Monitoriza\u00e7\u00e3o<\/strong> para as decis\u00f5es do otimizador, sem ativar o rastreio permanente.<\/p>\n\n\n<figure class=\"wp-block-image size-full is-resized\">\n  <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/09\/mariadb_optimizer_trace_4729.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>Casos de utiliza\u00e7\u00e3o t\u00edpicos e vantagens<\/h2>\n\n<p>Recorro ao Trace quando o EXPLAIN indica uma varredura completa inesperada e quero descobrir a raz\u00e3o pela qual um <strong>\u00cdndice<\/strong> quero saber. Da mesma forma, o trace fornece-me, no caso de muitas tabelas, a justifica\u00e7\u00e3o para a ordem de jun\u00e7\u00e3o escolhida, o que me indica o caminho para planos alternativos. Ao mudar de vers\u00e3o, guardo os registos antes e depois da atualiza\u00e7\u00e3o, para avaliar as altera\u00e7\u00f5es no comportamento do otimizador. No que diz respeito a quest\u00f5es estrat\u00e9gicas de ajuste, esta vis\u00e3o geral ajuda-me a <a href=\"https:\/\/webhosting.de\/pt\/o-otimizador-de-consultas-do-mariadb-explicado-internamente-uma-visao-sobre-o-ajuste-de-sql\/\">mecanismos internos do otimizador<\/a>, que associo aos resultados do Trace. \u00c9 assim que decido, de forma estruturada, se devo ajustar os \u00edndices, as estat\u00edsticas ou a formula\u00e7\u00e3o das consultas <strong>parafuso de ajuste<\/strong> coloque.<\/p>\n\n<h2>Boas pr\u00e1ticas para a produ\u00e7\u00e3o<\/h2>\n\n<p>Ativo o Trace de forma sistem\u00e1tica como <strong>Sess\u00e3o<\/strong>-Encerro o diagn\u00f3stico de forma adequada assim que tiver dados suficientes. Para registos de grande dimens\u00e3o, aumentei <code>optimizer_trace_max_mem_size<\/code> apenas a curto prazo e, depois, volto a definir o valor para um n\u00edvel mais baixo. Antes de partilhar ficheiros JSON, oculto constantes sens\u00edveis, textos de coment\u00e1rios ou indicadores empresariais. Utilizo o Trace especificamente como ferramenta de diagn\u00f3stico, enquanto, para monitoriza\u00e7\u00e3o cont\u00ednua, prefiro registos de consultas lentas, vistas de desempenho ou profiler externos. Esta disciplina mant\u00e9m os sistemas otimizados e evita <strong>Despesas gerais<\/strong> na atividade quotidiana.<\/p>\n\n\n<figure class=\"wp-block-image size-full is-resized\">\n  <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/09\/mariadb_optimizer_trace_3874.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>Rastreio do Optimizer no conjunto de ferramentas<\/h2>\n\n<p>Para um ajuste integral, represento a cadeia composta pela compreens\u00e3o do plano, pela an\u00e1lise das causas e pela medi\u00e7\u00e3o do sistema, e interligo as <strong>Conclus\u00f5es<\/strong>. O EXPLAIN mostra-me o plano, o ANALYZE confirma os custos reais e o trace fornece os pormenores por tr\u00e1s da decis\u00e3o. Paralelamente, analiso conceitos relacionados com o plano de execu\u00e7\u00e3o de consultas, para identificar padr\u00f5es na sele\u00e7\u00e3o de chaves, cardinalidades e estrat\u00e9gias de jun\u00e7\u00e3o. Um bom complemento a esta perspetiva \u00e9 a vis\u00e3o geral concisa sobre <a href=\"https:\/\/webhosting.de\/pt\/planos-de-execucao-de-consultas-de-bases-de-dados-otimizacao-do-alojamento-informacoes-sobre-o-desempenho\/\">Planos de execu\u00e7\u00e3o de consultas<\/a>, ao qual recorro quando tenho d\u00favidas sobre arquitetura. A partir da\u00ed, deduzo conclus\u00f5es s\u00f3lidas <strong>Prioridades<\/strong> para o trabalho de indexa\u00e7\u00e3o, reescritas e par\u00e2metros.<\/p>\n\n<h2>Aprofundar o tema: an\u00e1lise de intervalo e escolha de chaves<\/h2>\n\n<p>Muitas vezes, o \u00abtrace\u00bb cont\u00e9m um bloco <code>an\u00e1lise_de_intervalo<\/code> para cada tabela, onde consigo identificar quais os \u00edndices que podiam ser utilizados para acessos do tipo Range, Ref ou EQ-Ref. O otimizador compara a\u00ed alternativas como \u201erange no idx_a\u201c, \u201erange no idx_b\u201c ou \u201efull scan\u201c, atribui-lhes custos e o n\u00famero de linhas esperado e destaca a op\u00e7\u00e3o vencedora. Se verificar que um \u00edndice adequado foi rejeitado devido a custos elevados, analiso, em seguida, as seletividades e estat\u00edsticas subjacentes. Se as suposi\u00e7\u00f5es n\u00e3o estiverem corretas, pode ser necess\u00e1rio um <code>ANALISAR TABELA<\/code> (se for o caso, com estat\u00edsticas persistentes) ou a cria\u00e7\u00e3o de um <strong>\u00cdndice de cobertura<\/strong> anular a decis\u00e3o.<\/p>\n\n<p>Tamb\u00e9m \u00e9 \u00fatil analisar as divis\u00f5es dos \u00edndices compostos: o trace documenta se a condi\u00e7\u00e3o utiliza apenas a primeira coluna do \u00edndice ou se existem predicados adicionais que podem ser aplicados, tornando outras colunas-chave efetivas. A partir da\u00ed, deduzo se devo reformular os predicados (por exemplo, evitando fun\u00e7\u00f5es) ou alargar o \u00edndice de forma a abranger os filtros e ordena\u00e7\u00f5es t\u00edpicos.<\/p>\n\n<h2>Juntas em pormenor: semijuntas, BKA\/MRR e buffer de juntas<\/h2>\n\n<p>Nas consultas com v\u00e1rias tabelas, as sec\u00e7\u00f5es de rastreio mostram se foi considerada alguma estrat\u00e9gia de semijoin e, em caso afirmativo, qual (por exemplo, FirstMatch, DuplicateWeedout, LooseScan ou Materialization). Consigo perceber ali por que raz\u00e3o uma variante foi rejeitada \u2013 por exemplo, devido a custos de materializa\u00e7\u00e3o elevados ou a uma seletividade demasiado baixa. Al\u00e9m disso, <strong>Acesso por chave em lote (BKA)<\/strong> e <strong>Leitura multi-intervalo (MRR)<\/strong> aparecem no trace, caso estejam ativadas. Estas t\u00e9cnicas agrupam as pesquisas de chaves e melhoram a localidade da cache. Se o BKA\/MRR n\u00e3o aparecerem no trace, verifico <code>optimizer_switch<\/code> e par\u00e2metros como <code>join_cache_level<\/code>. Em cargas de trabalho com muitas pesquisas aleat\u00f3rias de chaves, \u00e9 poss\u00edvel acelerar significativamente a fase de jun\u00e7\u00e3o, o que pode ser verificado com o comando EXPLAIN ANALYZE.<\/p>\n\n<p>Outro fator decisivo \u00e9 o tamanho e o tipo do buffer de jun\u00e7\u00e3o: o trace revela se foram executadas variantes de Nested Loop com ou sem buffer e em que ponto os filtros entram em a\u00e7\u00e3o. Avalio se a cria\u00e7\u00e3o de \u00edndices adicionais nas chaves de jun\u00e7\u00e3o ou uma reescrita para reduzir os resultados interm\u00e9dios constitui a op\u00e7\u00e3o mais eficiente do que aumentar as dimens\u00f5es dos buffers.<\/p>\n\n<h2>Subconsultas, tabelas derivadas e vistas<\/h2>\n\n<p>Em <code>prepara\u00e7\u00e3o_de_jun\u00e7\u00e3o<\/code> Na minha opini\u00e3o, se as subconsultas na forma EXISTS\/IN em <strong>Semijoins<\/strong> foram transformados (<code>in_to_exists<\/code>), se as tabelas derivadas foram fundidas (<code>derived_merge<\/code>) ou se concretizaram e se <strong>Condi\u00e7\u00e3o Flex\u00e3o<\/strong> at\u00e9 \u00e0s tabelas derivadas. Estes passos s\u00e3o decisivos, porque a aus\u00eancia de uma fus\u00e3o pode levar a uma materializa\u00e7\u00e3o dispendiosa. Se, no trace, observar repetidamente decis\u00f5es de materializa\u00e7\u00e3o com custos elevados, verifico se existe uma <code>STRAIGHT_JOIN<\/code>, uma sugest\u00e3o ou uma reorganiza\u00e7\u00e3o da consulta (por exemplo, Common Table Expressions com filtros espec\u00edficos) leva o motor a adotar uma estrat\u00e9gia mais eficiente. No caso das vistas, verifico se o otimizador resolve adequadamente o conte\u00fado da vista ou se faltam \u00edndices adicionais na tabela subjacente.<\/p>\n\n<h2>Particionamento e poda<\/h2>\n\n<p>No caso de tabelas particionadas, o rastreio mostra quais as parti\u00e7\u00f5es que foram exclu\u00eddas com base nas chaves de parti\u00e7\u00e3o e nos predicados (<strong>Poda de parti\u00e7\u00f5es<\/strong>). Se a poda esperada n\u00e3o ocorrer, isso \u00e9 um sinal de que os filtros devem ser formulados mais cedo e de forma mais seletiva com base na chave de parti\u00e7\u00e3o. Presto tamb\u00e9m aten\u00e7\u00e3o \u00e0 intera\u00e7\u00e3o entre o particionamento e os \u00edndices: se faltarem \u00edndices locais ou globais, o motor pode verificar um n\u00famero excessivo de linhas, apesar da poda, o que se torna vis\u00edvel no rastreio atrav\u00e9s de custos de varredura elevados.<\/p>\n\n<h2>Verificar de forma espec\u00edfica as sugest\u00f5es, as especifica\u00e7\u00f5es de \u00edndice e o optimizer_switch<\/h2>\n\n<p>Utilizo o Trace para verificar o efeito das sugest\u00f5es e dos comutadores de par\u00e2metros <strong>ocupar<\/strong>. Se eu colocar, por exemplo,. <code>\u00cdNDICE DE FOR\u00c7A<\/code> ou uma sugest\u00e3o do otimizador, consigo ver no registo se a alternativa foi realmente imposta e como foi avaliada. Atrav\u00e9s de <code>optimizer_switch<\/code> posso ativar ou desativar temporariamente estrat\u00e9gias (por exemplo, para decis\u00f5es de semijoin, index_merge ou derived_merge). O registo serve-me ent\u00e3o como prova para verificar se o motor aceitou as especifica\u00e7\u00f5es ou se outras restri\u00e7\u00f5es (por exemplo, cardinalidades) continuam a prevalecer. Opcionalmente, utilizo sinalizadores de formata\u00e7\u00e3o como <code>one_line<\/code> ou <code>end_markers<\/code> em <code>optimizer_trace<\/code>-String, para adaptar a legibilidade \u00e0 minha ferramenta de an\u00e1lise.<\/p>\n\n<h2>Update\/DELETE e percursos de grava\u00e7\u00e3o<\/h2>\n\n<p>O Optimizer Trace n\u00e3o se limita \u00e0s instru\u00e7\u00f5es SELECT. Tamb\u00e9m nas instru\u00e7\u00f5es UPDATE e DELETE consigo ver como s\u00e3o escolhidos os m\u00e9todos de acesso e se os filtros s\u00e3o aplicados com anteced\u00eancia suficiente para manter baixo o n\u00famero de linhas afetadas. Verifico se um filtro WHERE n\u00e3o \u00e9 sarg\u00e1vel ou se a aus\u00eancia de um \u00edndice leva a uma fase de varredura abrangente antes de a altera\u00e7\u00e3o propriamente dita ser executada. A partir do Trace, deduzo se um \u00edndice compacto (por exemplo, apenas as colunas necess\u00e1rias) evita acessos desnecess\u00e1rios de ida e volta e, assim, reduz os bloqueios e o volume de registo.<\/p>\n\n<h2>Seguran\u00e7a, privil\u00e9gios e instru\u00e7\u00f5es preparadas<\/h2>\n\n<p>Para poder ler a faixa na \u00edntegra, preciso de privil\u00e9gios de objeto suficientes \u2013 se estes n\u00e3o existirem, o campo indica que <code>INSUFFICIENT_PRIVILEGES<\/code> Restri\u00e7\u00f5es. Por isso, em cen\u00e1rios pr\u00f3ximos da produ\u00e7\u00e3o, utilizo os mesmos dados de acesso que a aplica\u00e7\u00e3o ou uma conta de diagn\u00f3stico com autoriza\u00e7\u00f5es espec\u00edficas. No caso das instru\u00e7\u00f5es preparadas, o rastreio apresenta normalmente a forma otimizada com os par\u00e2metros j\u00e1 vinculados, o que me permite avaliar as seletividades sem revelar constantes sens\u00edveis. Se tiver de partilhar rastreios, oculto os valores dos par\u00e2metros ou substituo-os por intervalos representativos, a fim de cumprir os requisitos de prote\u00e7\u00e3o de dados.<\/p>\n\n<h2>Automatiza\u00e7\u00e3o: registar, diferenciar e documentar os tra\u00e7os<\/h2>\n\n<p>Para garantir a reprodutibilidade das an\u00e1lises, guardo traces de forma aleat\u00f3ria numa tabela de diagn\u00f3stico e atribuo-lhes metadados, tais como esquema, vers\u00e3o, vari\u00e1veis de sess\u00e3o e carimbo de data\/hora. Desta forma, posso, antes e depois de altera\u00e7\u00f5es no \u00edndice ou atualiza\u00e7\u00f5es de vers\u00e3o, <strong>diffen<\/strong>, quais as decis\u00f5es que foram adiadas. \u00c9 pr\u00e1tico organizar os blocos <code>planos_de_execu\u00e7\u00e3o_considerados<\/code> e <code>rows_estimation<\/code> armazenar separadamente, para comparar rapidamente as altera\u00e7\u00f5es nos custos. Pequenas consultas auxiliares extraem-me a ordem de jun\u00e7\u00e3o selecionada e os custos calculados \u2013 por exemplo, com <code>JSON_EXTRACT(TRACE, '$.join_optimization.considered_execution_plans')<\/code> \u2013 e guardam o resultado juntamente com os resultados dos comandos EXPLAIN e ANALYZE. Desta forma, obt\u00e9m-se uma documenta\u00e7\u00e3o fi\u00e1vel para cada etapa do ajuste.<\/p>\n\n<h2>Limita\u00e7\u00f5es, particularidades de cada vers\u00e3o e compara\u00e7\u00e3o com o MySQL<\/h2>\n\n<p>As estruturas-chave do trace seguem o modelo do MySQL; no entanto, os detalhes e os nomes dos campos podem variar ligeiramente, dependendo da vers\u00e3o do MariaDB. Por isso, vou centrar a minha aten\u00e7\u00e3o na <strong>sem\u00e2nticos<\/strong> Sec\u00e7\u00f5es (Rewrites, Rows-Estimation, planos considerados, Condition-Attachments), em vez de me deixar irritar por diferen\u00e7as meramente cosm\u00e9ticas. Importante: No MariaDB, o foco recai sobre a \u00faltima instru\u00e7\u00e3o da liga\u00e7\u00e3o ativa. Quem analisa muitas instru\u00e7\u00f5es consecutivas deve, por isso, ler os dados imediatamente ap\u00f3s a execu\u00e7\u00e3o ou de forma automatizada atrav\u00e9s de um hook, para que nenhum rasto relevante seja sobrescrito. No caso de ficheiros JSON muito grandes, tenho em conta as necessidades de mem\u00f3ria e compreendo <code>MISSING_BYTES_BEYOND_MAX_MEM_SIZE<\/code> como um convite para aumentar temporariamente o limite e voltar a executar a an\u00e1lise.<\/p>\n\n<h2>Extra\u00e7\u00f5es concretas de JSON para o dia-a-dia<\/h2>\n\n<p>Para terminar, eis alguns excertos concisos que utilizo frequentemente na pr\u00e1tica para ir direto ao essencial:<\/p>\n\n<ul>\n  <li>Ordem de jun\u00e7\u00e3o selecionada e listas de candidatos: extraio os prefixos do plano e a tabela associada a cada um, para poder compreender a sequ\u00eancia de decis\u00f5es.<\/li>\n  <li>Alternativas de intervalos e custos: extraio a lista dos \u00edndices avaliados para as tabelas mais seletivas, a fim de avaliar com precis\u00e3o as reescritas ou novos \u00edndices.<\/li>\n  <li>Filtros aplicados desde cedo: Estou a ler o <code>atribuir_condi\u00e7\u00f5es_a_tabelas<\/code>-sec\u00e7\u00f5es, para garantir que os predicados fortes fiquem o mais pr\u00f3ximo poss\u00edvel da fonte de dados.<\/li>\n<\/ul>\n\n<p>Com poucas visualiza\u00e7\u00f5es destas extra\u00e7\u00f5es, tenho uma \u201elente de leitura\u201c simplificada para as decis\u00f5es do otimizador, que ativo quando necess\u00e1rio nas sess\u00f5es de diagn\u00f3stico e desativo novamente a seguir.<\/p>\n\n<h2>Obst\u00e1culos frequentes e resolu\u00e7\u00e3o de problemas<\/h2>\n\n<p>Se faltarem histogramas ou se as estat\u00edsticas estiverem desatualizadas, as estimativas ficam erradas e geram <strong>Planos<\/strong> com an\u00e1lises completas desnecess\u00e1rias. Se observar cardinalidades muito divergentes no trace, atualizo as estat\u00edsticas, defino \u00edndices adequados ou reformulo os filtros de forma a torn\u00e1-los mais eficientes. Identifico traces demasiado sucintos atrav\u00e9s de <code>MISSING_BYTES_BEYOND_MAX_MEM_SIZE<\/code> e respondo com um limite temporariamente mais elevado. Se o ANALYZE apresentar melhores tempos de execu\u00e7\u00e3o para um caminho alternativo, verifico no trace qual o fator de custo que favoreceu a variante escolhida. Assim, vou colmatando, passo a passo, as lacunas de conhecimento e consigo <strong>Clareza<\/strong> sobre a l\u00f3gica de decis\u00e3o.<\/p>\n\n\n<figure class=\"wp-block-image size-full is-resized\">\n  <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/09\/mariadb-optimizer-trace-4829.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>Brevemente resumido<\/h2>\n\n<p>O MariaDB Optimizer Trace explica-me, num documento JSON, como o motor reformula as consultas, estima o n\u00famero de linhas, compara planos e, por fim, uma <strong>Sequ\u00eancia<\/strong> seleciona. Ativo-o por sess\u00e3o, leio a faixa, verifico <code>prepara\u00e7\u00e3o_de_jun\u00e7\u00e3o<\/code> e <code>otimiza\u00e7\u00e3o de jun\u00e7\u00f5es<\/code> e associo essas conclus\u00f5es ao EXPLAIN\/ANALYZE. A partir das raz\u00f5es para a rejei\u00e7\u00e3o de \u00edndices, filtros tardios ou estimativas erradas, deduzo medidas concretas: melhores \u00edndices, estat\u00edsticas mais atualizadas e formula\u00e7\u00f5es claras das consultas. Com fun\u00e7\u00f5es JSON, extraio trechos, identifico padr\u00f5es e documento as decis\u00f5es de forma reproduz\u00edvel. Desta forma, consigo tamb\u00e9m processar cargas de trabalho SQL extensas de forma fi\u00e1vel <strong>Desempenho<\/strong> e asseguro que as decis\u00f5es relativas ao tuning sejam compreens\u00edveis.<\/p>","protected":false},"excerpt":{"rendered":"<p>Aprenda a utilizar o MariaDB Optimizer Trace para analisar e otimizar consultas SQL complexas. Este artigo explica como ativar, a estrutura JSON e a interpreta\u00e7\u00e3o do Optimizer Trace para obter um melhor desempenho.<\/p>","protected":false},"author":1,"featured_media":21324,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[781],"tags":[],"class_list":["post-21331","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-datenbanken-administration-anleitungen"],"acf":[],"_wp_attached_file":null,"_wp_attachment_metadata":null,"litespeed-optimize-size":null,"litespeed-optimize-set":null,"_elementor_source_image_hash":null,"_wp_attachment_image_alt":null,"stockpack_author_name":null,"stockpack_author_url":null,"stockpack_provider":null,"stockpack_image_url":null,"stockpack_license":null,"stockpack_license_url":null,"stockpack_modification":null,"color":null,"original_id":null,"original_url":null,"original_link":null,"unsplash_location":null,"unsplash_sponsor":null,"unsplash_exif":null,"unsplash_attachment_metadata":null,"_elementor_is_screenshot":null,"surfer_file_name":null,"surfer_file_original_url":null,"envato_tk_source_kit":null,"envato_tk_source_index":null,"envato_tk_manifest":null,"envato_tk_folder_name":null,"envato_tk_builder":null,"envato_elements_download_event":null,"_menu_item_type":null,"_menu_item_menu_item_parent":null,"_menu_item_object_id":null,"_menu_item_object":null,"_menu_item_target":null,"_menu_item_classes":null,"_menu_item_xfn":null,"_menu_item_url":null,"_trp_menu_languages":null,"rank_math_primary_category":null,"rank_math_title":null,"inline_featured_image":null,"_yoast_wpseo_primary_category":null,"rank_math_schema_blogposting":null,"rank_math_schema_videoobject":null,"_oembed_049c719bc4a9f89deaead66a7da9fddc":null,"_oembed_time_049c719bc4a9f89deaead66a7da9fddc":null,"_yoast_wpseo_focuskw":null,"_yoast_wpseo_linkdex":null,"_oembed_27e3473bf8bec795fbeb3a9d38489348":null,"_oembed_c3b0f6959478faf92a1f343d8f96b19e":null,"_trp_translated_slug_en_us":null,"_wp_desired_post_slug":null,"_yoast_wpseo_title":null,"tldname":null,"tldpreis":null,"tldrubrik":null,"tldpolicylink":null,"tldsize":null,"tldregistrierungsdauer":null,"tldtransfer":null,"tldwhoisprivacy":null,"tldregistrarchange":null,"tldregistrantchange":null,"tldwhoisupdate":null,"tldnameserverupdate":null,"tlddeletesofort":null,"tlddeleteexpire":null,"tldumlaute":null,"tldrestore":null,"tldsubcategory":null,"tldbildname":null,"tldbildurl":null,"tldclean":null,"tldcategory":null,"tldpolicy":null,"tldbesonderheiten":null,"tld_bedeutung":null,"_oembed_d167040d816d8f94c072940c8009f5f8":null,"_oembed_b0a0fa59ef14f8870da2c63f2027d064":null,"_oembed_4792fa4dfb2a8f09ab950a73b7f313ba":null,"_oembed_33ceb1fe54a8ab775d9410abf699878d":null,"_oembed_fd7014d14d919b45ec004937c0db9335":null,"_oembed_21a029d076783ec3e8042698c351bd7e":null,"_oembed_be5ea8a0c7b18e658f08cc571a909452":null,"_oembed_a9ca7a298b19f9b48ec5914e010294d2":null,"_oembed_f8db6b27d08a2bb1f920e7647808899a":null,"_oembed_168ebde5096e77d8a89326519af9e022":null,"_oembed_cdb76f1b345b42743edfe25481b6f98f":null,"_oembed_87b0613611ae54e86e8864265404b0a1":null,"_oembed_27aa0e5cf3f1bb4bc416a4641a5ac273":null,"_oembed_time_27aa0e5cf3f1bb4bc416a4641a5ac273":null,"_tldname":null,"_tldclean":null,"_tldpreis":null,"_tldcategory":null,"_tldsubcategory":null,"_tldpolicy":null,"_tldpolicylink":null,"_tldsize":null,"_tldregistrierungsdauer":null,"_tldtransfer":null,"_tldwhoisprivacy":null,"_tldregistrarchange":null,"_tldregistrantchange":null,"_tldwhoisupdate":null,"_tldnameserverupdate":null,"_tlddeletesofort":null,"_tlddeleteexpire":null,"_tldumlaute":null,"_tldrestore":null,"_tldbildname":null,"_tldbildurl":null,"_tld_bedeutung":null,"_tldbesonderheiten":null,"_oembed_ad96e4112edb9f8ffa35731d4098bc6b":null,"_oembed_8357e2b8a2575c74ed5978f262a10126":null,"_oembed_3d5fea5103dd0d22ec5d6a33eff7f863":null,"_eael_widget_elements":null,"_oembed_0d8a206f09633e3d62b95a15a4dd0487":null,"_oembed_time_0d8a206f09633e3d62b95a15a4dd0487":null,"_aioseo_description":null,"_eb_attr":null,"_eb_data_table":null,"_oembed_819a879e7da16dd629cfd15a97334c8a":null,"_oembed_time_819a879e7da16dd629cfd15a97334c8a":null,"_acf_changed":null,"_wpcode_auto_insert":null,"_edit_last":null,"_edit_lock":null,"_oembed_e7b913c6c84084ed9702cb4feb012ddd":null,"_oembed_bfde9e10f59a17b85fc8917fa7edf782":null,"_oembed_time_bfde9e10f59a17b85fc8917fa7edf782":null,"_oembed_03514b67990db061d7c4672de26dc514":null,"_oembed_time_03514b67990db061d7c4672de26dc514":null,"rank_math_news_sitemap_robots":null,"rank_math_robots":null,"_eael_post_view_count":"63","_trp_automatically_translated_slug_ru_ru":null,"_trp_automatically_translated_slug_et":null,"_trp_automatically_translated_slug_lv":null,"_trp_automatically_translated_slug_fr_fr":null,"_trp_automatically_translated_slug_en_us":null,"_wp_old_slug":null,"_trp_automatically_translated_slug_da_dk":null,"_trp_automatically_translated_slug_pl_pl":null,"_trp_automatically_translated_slug_es_es":null,"_trp_automatically_translated_slug_hu_hu":null,"_trp_automatically_translated_slug_fi":null,"_trp_automatically_translated_slug_ja":null,"_trp_automatically_translated_slug_lt_lt":null,"_elementor_edit_mode":null,"_elementor_template_type":null,"_elementor_version":null,"_elementor_pro_version":null,"_wp_page_template":null,"_elementor_page_settings":null,"_elementor_data":null,"_elementor_css":null,"_elementor_conditions":null,"_happyaddons_elements_cache":null,"_oembed_75446120c39305f0da0ccd147f6de9cb":null,"_oembed_time_75446120c39305f0da0ccd147f6de9cb":null,"_oembed_3efb2c3e76a18143e7207993a2a6939a":null,"_oembed_time_3efb2c3e76a18143e7207993a2a6939a":null,"_oembed_59808117857ddf57e478a31d79f76e4d":null,"_oembed_time_59808117857ddf57e478a31d79f76e4d":null,"_oembed_965c5b49aa8d22ce37dfb3bde0268600":null,"_oembed_time_965c5b49aa8d22ce37dfb3bde0268600":null,"_oembed_81002f7ee3604f645db4ebcfd1912acf":null,"_oembed_time_81002f7ee3604f645db4ebcfd1912acf":null,"_elementor_screenshot":null,"_oembed_7ea3429961cf98fa85da9747683af827":null,"_oembed_time_7ea3429961cf98fa85da9747683af827":null,"_elementor_controls_usage":null,"_elementor_page_assets":[],"_elementor_screenshot_failed":null,"theplus_transient_widgets":null,"_eael_custom_js":null,"_wp_old_date":null,"_trp_automatically_translated_slug_it_it":null,"_trp_automatically_translated_slug_pt_pt":null,"_trp_automatically_translated_slug_zh_cn":null,"_trp_automatically_translated_slug_nl_nl":null,"_trp_automatically_translated_slug_pt_br":null,"_trp_automatically_translated_slug_sv_se":null,"rank_math_analytic_object_id":null,"rank_math_internal_links_processed":"1","_trp_automatically_translated_slug_ro_ro":null,"_trp_automatically_translated_slug_sk_sk":null,"_trp_automatically_translated_slug_bg_bg":null,"_trp_automatically_translated_slug_sl_si":null,"litespeed_vpi_list":null,"litespeed_vpi_list_mobile":null,"rank_math_seo_score":null,"rank_math_contentai_score":null,"ilj_limitincominglinks":null,"ilj_maxincominglinks":null,"ilj_limitoutgoinglinks":null,"ilj_maxoutgoinglinks":null,"ilj_limitlinksperparagraph":null,"ilj_linksperparagraph":null,"ilj_blacklistdefinition":null,"ilj_linkdefinition":null,"_eb_reusable_block_ids":null,"rank_math_focus_keyword":"optimizer trace","rank_math_og_content_image":null,"_yoast_wpseo_metadesc":null,"_yoast_wpseo_content_score":null,"_yoast_wpseo_focuskeywords":null,"_yoast_wpseo_keywordsynonyms":null,"_yoast_wpseo_estimated-reading-time-minutes":null,"rank_math_description":null,"surfer_last_post_update":null,"surfer_last_post_update_direction":null,"surfer_keywords":null,"surfer_location":null,"surfer_draft_id":null,"surfer_permalink_hash":null,"surfer_scrape_ready":null,"_thumbnail_id":"21324","footnotes":null,"_links":{"self":[{"href":"https:\/\/webhosting.de\/pt\/wp-json\/wp\/v2\/posts\/21331","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/webhosting.de\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/webhosting.de\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/webhosting.de\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/webhosting.de\/pt\/wp-json\/wp\/v2\/comments?post=21331"}],"version-history":[{"count":0,"href":"https:\/\/webhosting.de\/pt\/wp-json\/wp\/v2\/posts\/21331\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/webhosting.de\/pt\/wp-json\/wp\/v2\/media\/21324"}],"wp:attachment":[{"href":"https:\/\/webhosting.de\/pt\/wp-json\/wp\/v2\/media?parent=21331"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/webhosting.de\/pt\/wp-json\/wp\/v2\/categories?post=21331"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/webhosting.de\/pt\/wp-json\/wp\/v2\/tags?post=21331"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}