{"id":20930,"date":"2026-08-23T15:05:18","date_gmt":"2026-08-23T13:05:18","guid":{"rendered":"https:\/\/webhosting.de\/mariadb-query-optimizer-intern-erklaert-sql-tuning-insight\/"},"modified":"2026-08-23T15:05:18","modified_gmt":"2026-08-23T13:05:18","slug":"o-otimizador-de-consultas-do-mariadb-explicado-internamente-uma-visao-sobre-o-ajuste-de-sql","status":"publish","type":"post","link":"https:\/\/webhosting.de\/pt\/mariadb-query-optimizer-intern-erklaert-sql-tuning-insight\/","title":{"rendered":"O Otimizador de Consultas do MariaDB explicado em pormenor: no\u00e7\u00f5es b\u00e1sicas, planos e aplica\u00e7\u00e3o pr\u00e1tica"},"content":{"rendered":"<p>Vou explicar o <strong>Otimizador do MariaDB<\/strong> Na pr\u00e1tica: como ele elabora planos, estima custos e por que raz\u00e3o, por vezes, se engana. Assim, aprender\u00e1s a interpretar o plano de execu\u00e7\u00e3o SQL de forma objetiva, a utilizar \u00edndices de forma sensata e a orientar o otimizador com base em factos, em vez de no instinto.<\/p>\n\n<h2>Pontos centrais<\/h2>\n\n<p>Para come\u00e7ar, vou resumir brevemente os elementos mais importantes, para que possas contextualizar as sec\u00e7\u00f5es seguintes de forma espec\u00edfica e o <strong>Vis\u00e3o geral<\/strong> mant\u00e9ns.<\/p>\n<ul>\n  <li><strong>Fases<\/strong>: A an\u00e1lise, a prepara\u00e7\u00e3o, a otimiza\u00e7\u00e3o e a execu\u00e7\u00e3o constituem o ciclo de vida de cada consulta.<\/li>\n  <li><strong>Modelo de custos<\/strong>: Os valores baseados no tempo, na ordem dos microssegundos, controlam a sele\u00e7\u00e3o de \u00edndices, as varreduras e as sequ\u00eancias de jun\u00e7\u00f5es.<\/li>\n  <li><strong>Estat\u00edsticas<\/strong>: A cardinalidade e os histogramas determinam a estimativa da seletividade.<\/li>\n  <li><strong>Transpar\u00eancia<\/strong>: EXPLAIN, EXPLAIN ANALYZE e Optimizer Trace abrem a \u00abcaixa preta\u00bb.<\/li>\n  <li><strong>Afina\u00e7\u00e3o<\/strong>: Os \u00edndices, a reescrita de consultas, o comando ANALYZE TABLE e os par\u00e2metros de custo aumentam a velocidade.<\/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\/08\/mariaDB-query-plans-9842.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>Ciclo de vida de uma consulta no MariaDB<\/h2>\n\n<p>Antes de se concretizar um plano, uma consulta passa por quatro etapas, que eu verifico de forma espec\u00edfica no dia a dia, para <strong>Causas<\/strong> para identificar lentid\u00e3o. Durante a an\u00e1lise, o MariaDB converte o SQL numa estrutura interna; \u00e9 aqui que os erros de sintaxe s\u00e3o detetados. Na fase de prepara\u00e7\u00e3o, o motor verifica tabelas, colunas e \u00edndices potenciais e realiza transforma\u00e7\u00f5es simples. Segue-se ent\u00e3o a otimiza\u00e7\u00e3o, na qual s\u00e3o calculados planos candidatos e avaliados com base num modelo de custos. Na execu\u00e7\u00e3o, o servidor implementa o plano selecionado passo a passo: ler, unir, filtrar, devolver.<\/p>\n\n<p>Distingo claramente os erros de an\u00e1lise por fase, porque assim os diagn\u00f3sticos surtem efeito mais rapidamente e <strong>Medidas<\/strong> agir de forma direcionada. Na maioria das vezes, os problemas de desempenho t\u00eam origem na otimiza\u00e7\u00e3o: estimativas erradas, \u00edndices em falta ou sequ\u00eancias de jun\u00e7\u00f5es desfavor\u00e1veis. Os erros de an\u00e1lise s\u00e3o triviais, mas a fase de prepara\u00e7\u00e3o j\u00e1 pode envolver t\u00e9cnicas como a resolu\u00e7\u00e3o de vistas ou a reformula\u00e7\u00e3o de subconsultas. Na fase de execu\u00e7\u00e3o, as inefici\u00eancias tornam-se ent\u00e3o evidentes, caso tenha sido previamente selecionada uma varredura completa. Por isso, come\u00e7o sempre a minha an\u00e1lise com uma revis\u00e3o estruturada de todas as quatro etapas.<\/p>\n\n<h2>Como o Optimizer toma as suas decis\u00f5es internamente<\/h2>\n\n<p>O MariaDB funciona com base nos custos e avalia execu\u00e7\u00f5es alternativas atrav\u00e9s de uma <strong>Fun\u00e7\u00e3o de custo<\/strong>. Para cada variante, o servidor estima o n\u00famero de linhas lidas, a seletividade das condi\u00e7\u00f5es WHERE\/ON, os tipos de acesso, como Table Scan, Index Scan e Range Scan, bem como o tempo necess\u00e1rio para cada opera\u00e7\u00e3o. Internamente, o servidor distingue entre `join_preparation` e `join_optimization`. Em `join_preparation`, s\u00e3o executadas reescritas de consultas, simplifica\u00e7\u00f5es de condi\u00e7\u00f5es, transforma\u00e7\u00f5es de subconsultas e resolu\u00e7\u00f5es de vistas. O `join_optimization` calcula as ordens de jun\u00e7\u00e3o, verifica candidatos a \u00edndices atrav\u00e9s do `ref_optimizer_key_uses`, estima o n\u00famero de linhas atrav\u00e9s de varreduras de intervalo e atribui as condi\u00e7\u00f5es a tabelas espec\u00edficas o mais cedo poss\u00edvel.<\/p>\n\n<p>Este mecanismo explica por que raz\u00e3o um pequeno filtro colocado no local errado pode causar danos dispendiosos <strong>Consequ\u00eancias<\/strong> tem. Se o `attaching_conditions_to_tables` ocorrer tarde, o plano arrasta desnecessariamente muitas linhas pelas jun\u00e7\u00f5es. Se as estat\u00edsticas estiverem desatualizadas, o `rows_estimation` e a `Selectivity` apresentam resultados errados; o otimizador recorre ent\u00e3o a caminhos de acesso aparentemente favor\u00e1veis, mas que, na realidade, s\u00e3o lentos. \u00c9 precisamente nestes pontos que intervenho: estat\u00edsticas melhores, predicados mais claros, \u00edndices compostos bem organizados. Depois disso, a escolha do plano muda frequentemente de forma not\u00e1vel.<\/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\/08\/MariaDBQueryOptKonferenz1234.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>Modelo de custos a partir do MariaDB 11.0<\/h2>\n\n<p>As vers\u00f5es atuais j\u00e1 n\u00e3o avaliam o trabalho de forma aproximada com base em pesos, mas sim com <strong>Microssegundos<\/strong> para opera\u00e7\u00f5es de armazenamento espec\u00edficas. Par\u00e2metros como optimizer_disk_read_cost, optimizer_disk_read_ratio e optimizer_where_cost aproximam o modelo dos tempos de execu\u00e7\u00e3o reais. Assim, o otimizador compara a varredura de intervalo de \u00edndice com a varredura completa com base em pressupostos de tempo reais. O LAST_QUERY_COST apresenta o custo total estimado e, frequentemente, correlaciona-se significativamente melhor com a realidade do que anteriormente. Para sistemas com grande volume de dados, esta abordagem mais refinada compensa imediatamente.<\/p>\n\n<p>Calibro o modelo com cuidado quando as caracter\u00edsticas do hardware contrariam os pressupostos padr\u00e3o e, consequentemente, a <strong>Escolha do plano<\/strong> distorcer. Os SSDs NVMe, as mem\u00f3rias distribu\u00eddas ou as caches espec\u00edficas podem alterar significativamente a rela\u00e7\u00e3o de disco e os tempos de leitura. Pequenos ajustes nos \u00aboptimizer_costs\u00bb fazem com que o MariaDB d\u00ea prefer\u00eancia a percursos mais adequados. Documento cada altera\u00e7\u00e3o e, em seguida, verifico o EXPLAIN ANALYZE para medir o impacto. Sem medi\u00e7\u00e3o, o ajuste torna-se uma lotaria.<\/p>\n\n<h2>Seletividade, estat\u00edsticas e histogramas<\/h2>\n\n<p>Boas estimativas come\u00e7am com dados precisos <strong>cardinalidade<\/strong> e de uma seletividade fi\u00e1vel. O MariaDB mant\u00e9m estat\u00edsticas sobre os diferentes valores de cada coluna e pode, opcionalmente, utilizar histogramas para as distribui\u00e7\u00f5es. S\u00e3o precisamente os dados irregulares \u2014 pontos de concentra\u00e7\u00e3o, distribui\u00e7\u00f5es de Zipf, padr\u00f5es sazonais \u2014 que beneficiam dos histogramas. Ap\u00f3s grandes altera\u00e7\u00f5es nos dados, executo o comando ANALYZE TABLE para que a otimiza\u00e7\u00e3o volte a basear-se em dados reais. Quem se esquecer disso corre o risco de realizar varreduras completas que s\u00e3o objetivamente incorretas.<\/p>\n\n<p>Vou programar o ANALYZE como uma tarefa regular, de acordo com <strong>Altera\u00e7\u00f5es<\/strong> no volume de dados e em tabelas cr\u00edticas. Em distribui\u00e7\u00f5es de colunas fortemente distorcidas, os histogramas ajudam a avaliar de forma realista a seletividade de valores singulares. Isto reduz as avalia\u00e7\u00f5es erradas em varreduras de intervalo e estrat\u00e9gias de fus\u00e3o. Em combina\u00e7\u00e3o com \u00edndices compostos adequados, a precis\u00e3o dos resultados melhora drasticamente. Resultado: tempos de execu\u00e7\u00e3o mais curtos e menos E\/S.<\/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\/08\/mariadb-query-optimizer-guide-4729.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>EXPLAIN e como ler os planos de execu\u00e7\u00e3o<\/h2>\n\n<p>Para tornar as decis\u00f5es vis\u00edveis, utilizo o EXPLAIN, o EXPLAIN EXTENDED e <strong>FORMATO=JSON<\/strong>. As colunas cl\u00e1ssicas oferecem uma vis\u00e3o geral r\u00e1pida: id, select_type, table, type, possible_keys, key, key_len, ref, rows e, se for o caso, filtered. Um \u00abtype=ALL\u00bb indica uma varredura completa, o que raramente \u00e9 desej\u00e1vel. \u00abFORMAT=JSON\u00bb mostra em detalhe como as condi\u00e7\u00f5es foram reorganizadas e quais os caminhos que o otimizador avaliou. No contexto da hospedagem, recomendo o guia 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 no alojamento<\/a>, para associar informa\u00e7\u00f5es do plano aos efeitos na infraestrutura.<\/p>\n\n<p>Para uma interpreta\u00e7\u00e3o r\u00e1pida, recorro a uma pequena tabela que resume os valores t\u00edpicos e, assim, <strong>Interpreta\u00e7\u00f5es incorrectas<\/strong> impedido.<\/p>\n\n<table>\n  <thead>\n    <tr>\n      <th>Campo EXPLAIN<\/th>\n      <th>Valor t\u00edpico<\/th>\n      <th>Significado na pr\u00e1tica<\/th>\n    <\/tr>\n  <\/thead>\n  <tbody>\n    <tr>\n      <td>tipo<\/td>\n      <td>ALL, range, ref, eq_ref, const<\/td>\n      <td>Quanto mais \u00e0 direita, mais seletivo; \u00abALL\u00bb indica uma verifica\u00e7\u00e3o completa.<\/td>\n    <\/tr>\n    <tr>\n      <td>possible_keys<\/td>\n      <td>Lista de \u00edndices<\/td>\n      <td>\u00cdndices que, em teoria, se encaixam; se faltam candidatos aqui, falta estrutura.<\/td>\n    <\/tr>\n    <tr>\n      <td>tecla<\/td>\n      <td>Nome do \u00edndice<\/td>\n      <td>\u00cdndice efetivamente utilizado; se estiver em branco, significa que n\u00e3o se utiliza o \u00edndice.<\/td>\n    <\/tr>\n    <tr>\n      <td>linhas<\/td>\n      <td>N\u00famero<\/td>\n      <td>Estimativa de linhas lidas; grande discrep\u00e2ncia em rela\u00e7\u00e3o \u00e0 realidade = estat\u00edstica incorreta.<\/td>\n    <\/tr>\n    <tr>\n      <td>filtrado<\/td>\n      <td>Por cento<\/td>\n      <td>Qual a quantidade que passa pelo filtro; muitas vezes, uma quantidade reduzida \u00e9 o ideal.<\/td>\n    <\/tr>\n  <\/tbody>\n<\/table>\n\n<h2>Por que \u00e9 que o Optimizer, por vezes, se engana<\/h2>\n\n<p>Nenhum modelo de custos se adapta a todas as situa\u00e7\u00f5es, por isso vou corrigir <strong>Erros<\/strong> de forma direcionada. Estat\u00edsticas desatualizadas levam a estimativas erradas de \u00abrows\u00bb e a sequ\u00eancias de jun\u00e7\u00f5es desfavor\u00e1veis. \u00cdndices compostos mal estruturados impedem a utiliza\u00e7\u00e3o do \u00edndice em filtros com v\u00e1rias colunas. Subconsultas muito aninhadas dificultam reescritas eficazes e bloqueiam a materializa\u00e7\u00e3o. Filtros ausentes ou enganosos obrigam o motor a mover muitas linhas antes que os predicados \u00fateis sejam aplicados.<\/p>\n\n<p>Em primeiro lugar, verifico se a formula\u00e7\u00e3o da consulta est\u00e1 de acordo com o <strong>\u00cdndice<\/strong> O que realmente funciona: regra do prefixo \u00e0 esquerda, ordem de ordena\u00e7\u00e3o adequada, evitar fun\u00e7\u00f5es nas colunas na cl\u00e1usula WHERE. Depois, verifico no EXPLAIN ANALYZE se a realidade confirma a estimativa. Se n\u00e3o for o caso, segue-se o ANALYZE TABLE e, se necess\u00e1rio, uma reescrita. S\u00f3 no final \u00e9 que recorro ao FORCE INDEX ou ao hinting, porque isso pode limitar otimiza\u00e7\u00f5es futuras.<\/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\/08\/mariadboptimizer_2219.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>Utilizar o Optimizer Trace de forma espec\u00edfica<\/h2>\n\n<p>Se o EXPLAIN n\u00e3o for suficiente, ativo o Optimizer Trace e acompanho <strong>Decis\u00f5es<\/strong> no registo JSON. A\u00ed consigo ver quais os planos que foram considerados, rejeitados ou aceites. Percebo por que raz\u00e3o uma condi\u00e7\u00e3o \u00e9 aplicada tardiamente ou por que raz\u00e3o um \u00edndice n\u00e3o foi selecionado. O registo tamb\u00e9m mostra como as condi\u00e7\u00f5es foram reorganizadas. Esta vis\u00e3o aprofunda a compreens\u00e3o e fornece alavancas concretas para o pr\u00f3ximo ajuste.<\/p>\n\n<p>Guardo as sec\u00e7\u00f5es relevantes do trace juntamente com o hash da consulta e <strong>Par\u00e2metros<\/strong>avaliar. Assim, mais tarde, posso comparar qual a altera\u00e7\u00e3o que teve que efeito. A documenta\u00e7\u00e3o do servidor MariaDB e v\u00e1rias apresenta\u00e7\u00f5es no ecossistema descrevem estes campos em pormenor (fonte: Documenta\u00e7\u00e3o do servidor MariaDB sobre o Query Optimizer e o Optimizer Trace). Com esta ferramenta, consigo identificar suposi\u00e7\u00f5es erradas mais rapidamente do que atrav\u00e9s do m\u00e9todo de tentativa e erro. Poupo tempo sobretudo em jun\u00e7\u00f5es complexas.<\/p>\n\n<h2>Na pr\u00e1tica: Otimiza\u00e7\u00e3o de bases de dados, passo a passo<\/h2>\n\n<p>Come\u00e7o cada otimiza\u00e7\u00e3o com uma <strong>Medi\u00e7\u00e3o<\/strong>. Identifico as consultas relacionadas com problemas atrav\u00e9s da monitoriza\u00e7\u00e3o e do <a href=\"https:\/\/webhosting.de\/pt\/mysql-slow-query-log-hosting-analyse-queryperf\/\">Registo de consultas lentas<\/a>. Em seguida, comparo o EXPLAIN com o EXPLAIN ANALYZE, para comparar o plano com a realidade. Adapto a estrat\u00e9gia de indexa\u00e7\u00e3o \u00e0s cl\u00e1usulas WHERE, JOIN e ORDER BY; alinho os \u00edndices compostos com os pontos de acesso mais frequentes. S\u00f3 utilizo o FORCE INDEX quando o otimizador, apesar de dispor de estat\u00edsticas corretas, escolhe o candidato errado.<\/p>\n\n<p>Cada etapa implica a manuten\u00e7\u00e3o da <strong>Estat\u00edsticas<\/strong>: ANALYZE TABLE em tabelas com grande volume de transa\u00e7\u00f5es, histogramas para distribui\u00e7\u00f5es assim\u00e9tricas. Simplifico subconsultas desnecess\u00e1rias, materializo resultados interm\u00e9dios quando necess\u00e1rio e elimino solu\u00e7\u00f5es alternativas antigas. No caso de hardware especial, verifico os optimizer_costs para garantir que o modelo de microssegundos est\u00e1 correto. Documento cada altera\u00e7\u00e3o com valores \u00abantes\u00bb e \u00abdepois\u00bb, para que o efeito permane\u00e7a verific\u00e1vel a longo prazo.<\/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\/08\/mariadb_query_optimizer_8390.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>Problemas t\u00edpicos dos otimizadores e respetivas solu\u00e7\u00f5es<\/h2>\n\n<p>Se o EXPLAIN mostrar type=ALL, apesar de o campo possible_keys estar preenchido, verifico primeiro <strong>Seletividade<\/strong>. Muitas vezes, a ordem das colunas no \u00edndice composto n\u00e3o \u00e9 adequada ou uma fun\u00e7\u00e3o impede a utiliza\u00e7\u00e3o do \u00edndice. Nesses casos, inverto a ordem, elimino fun\u00e7\u00f5es que causam problemas ou divido os predicados. Se a ordem das jun\u00e7\u00f5es estiver errada, verifico se \u00e9 poss\u00edvel aplicar uma filtragem antecipada, por exemplo, colocando a tabela mais seletiva em primeiro lugar. Sempre que faz sentido, converto subconsultas em jun\u00e7\u00f5es ou tabelas TEMPORARY.<\/p>\n\n<p>Tamb\u00e9m reconhe\u00e7o decis\u00f5es erradas quando estas se afastam significativamente <strong>linhas<\/strong> entre o planeado e a realidade. Nesse caso, o comando ANALYZE TABLE ou um histograma na coluna em quest\u00e3o podem ajudar. Se mesmo as estat\u00edsticas corretas n\u00e3o conduzirem ao resultado pretendido, considero a utiliza\u00e7\u00e3o de hints expl\u00edcitos. Antes disso, guardo uma verifica\u00e7\u00e3o cruzada e os valores medidos, para que vers\u00f5es posteriores do otimizador n\u00e3o sejam prejudicadas por dados armazenados. A disciplina na documenta\u00e7\u00e3o compensa neste caso.<\/p>\n\n<h2>Contexto de alojamento e aspetos operacionais<\/h2>\n\n<p>A qualidade das consultas e a infraestrutura t\u00eam de estar em sintonia; caso contr\u00e1rio, a aplica\u00e7\u00e3o desperdi\u00e7a o seu potencial <strong>Potencial<\/strong>. SSDs r\u00e1pidos, caches consistentes e uma configura\u00e7\u00e3o bem organizada s\u00e3o a base sobre a qual o Optimizer toma boas decis\u00f5es. Um tr\u00e1fego elevado n\u00e3o permite an\u00e1lises completas; algumas consultas mal elaboradas podem paralisar sistemas inteiros. Para ambientes MySQL\/MariaDB em produ\u00e7\u00e3o, fornecem orienta\u00e7\u00f5es pr\u00e1ticas como <a href=\"https:\/\/webhosting.de\/pt\/mysql-optimizer-query-hosting-otimizacao-serverboost\/\">Otimizador do MySQL<\/a> reflex\u00f5es \u00fateis sobre a combina\u00e7\u00e3o entre plano e plataforma. Quem tem em conta este aspeto evita os estrangulamentos antes que estes se agravem.<\/p>\n\n<p>Associo sempre a an\u00e1lise do plano a m\u00e9tricas relativas a <strong>E\/S<\/strong>, lat\u00eancia e concorr\u00eancia. Se os valores n\u00e3o corresponderem ao modelo de custos previsto, verifico os par\u00e2metros. Em seguida, analiso os tamanhos dos buffers, as cargas de trabalho paralelas e a distribui\u00e7\u00e3o dos hotsets. Com esta abordagem, consigo gerir as consultas e os recursos de forma harmoniosa e manter os picos de tr\u00e1fego sob controlo.<\/p>\n\n<h2>Caminhos de jun\u00e7\u00e3o e de acesso na pr\u00e1tica<\/h2>\n\n<p>Esclare\u00e7o muitos mal-entendidos explicando o <strong>Tipos de acesso<\/strong> ponderar de forma espec\u00edfica uns contra os outros. Um <em>intervalo<\/em>- ou <em>ref<\/em>-O acesso funciona quase sempre <em>TUDO<\/em>. No caso de liga\u00e7\u00f5es de igualdade com base em chaves \u00fanicas (<em>eq_ref<\/em>) os planos s\u00e3o particularmente est\u00e1veis. Al\u00e9m disso, verifico se um <strong>\u00cdndice de cobertura<\/strong> que atenda integralmente \u00e0 consulta: se todas as colunas necess\u00e1rias estiverem no \u00edndice, o MariaDB evita acessos dispendiosos \u00e0s tabelas. <strong>Press\u00e3o de condi\u00e7\u00e3o de \u00edndice (ICP)<\/strong> ajuda a verificar condi\u00e7\u00f5es WHERE adicionais j\u00e1 no \u00edndice \u2013 o que reduz o n\u00famero de linhas devolvidas e as opera\u00e7\u00f5es de E\/S.<\/p>\n\n<p>Sobre <strong>Fus\u00e3o de \u00edndices<\/strong> O MariaDB pode combinar v\u00e1rios \u00edndices (intersec\u00e7\u00e3o\/uni\u00e3o). Isto \u00e9 \u00fatil no caso de predicados OR ou de v\u00e1rias condi\u00e7\u00f5es de sele\u00e7\u00e3o, mas \u00e9 frequentemente mais lento do que um \u00edndice composto bem escolhido. Al\u00e9m disso, estou a avaliar <strong>MRR<\/strong> (Leitura multialcance) e <strong>BKA<\/strong> (Batched Key Access). O MRR ordena as chaves prim\u00e1rias a ler para suavizar as E\/S aleat\u00f3rias; o BKA agrupa as pesquisas de jun\u00e7\u00e3o e obt\u00e9m melhores resultados, sobretudo em jun\u00e7\u00f5es n\u00e3o sobrepostas. Na pr\u00e1tica, testo o BKA\/MRR atrav\u00e9s do `optimizer_switch` e verifico com o `EXPLAIN ANALYZE` se os padr\u00f5es de E\/S diminuem. Se, pelo contr\u00e1rio, o MariaDB recorrer ao <strong>Bloco de la\u00e7os aninhados<\/strong> (BNL), na maioria das vezes compensa utilizar um buffer de jun\u00e7\u00e3o maior (join_buffer_size) \u2013 ou uma reescrita que permita jun\u00e7\u00f5es por \u00edndice verdadeiras.<\/p>\n\n<pre><code>-- Exemplo: \u00cdndice composto para jun\u00e7\u00e3o + filtro + ordena\u00e7\u00e3o\nCREATE INDEX ix_orders_cust_status_created\n  ON orders (customer_id, status, created_at);\n\n-- Acesso t\u00edpico\nSELECT *\nFROM orders o\nJOIN customers c ON c.id = o.customer_id\nWHERE o.status = 'open' AND o.created_at &gt;= '2026-01-01'\nORDER BY o.created_at DESC\nLIMIT 50;\n<\/code><\/pre>\n\n<p>Com o \u00edndice acima referido, o otimizador pode escolher a ordem mais seletiva, avaliar os filtros numa fase inicial e, muitas vezes, efetuar a ordena\u00e7\u00e3o sem necessidade de uma ordena\u00e7\u00e3o em ficheiro adicional.<\/p>\n\n<h2>ORDER BY, GROUP BY, ordena\u00e7\u00e3o por ficheiros e tabelas tempor\u00e1rias<\/h2>\n\n<p>A ordena\u00e7\u00e3o e a agrega\u00e7\u00e3o demoram tempo. Eu garanto que <strong>ORDER BY<\/strong> e <strong>GRUPO POR<\/strong> podem ser executadas na ordem do \u00edndice. Isto funciona se o prefixo e a dire\u00e7\u00e3o corresponderem exatamente. Caso contr\u00e1rio, aplica-se uma <strong>Classifica\u00e7\u00e3o de ficheiros<\/strong> com buffer de ordena\u00e7\u00e3o (sort_buffer_size) e, se necess\u00e1rio, uma tabela tempor\u00e1ria. Se o conjunto de resultados incluir colunas TEXT\/BLOB largas, o MariaDB torna-se mais r\u00e1pido <em>no disco<\/em> Tabelas TEMP (Aria). Prevenho este problema selecionando apenas as colunas necess\u00e1rias, carregando campos grandes apenas no final ou utilizando prefixos com comprimento limitado.<\/p>\n\n<p>Nas agrega\u00e7\u00f5es, sempre que poss\u00edvel, utilizo, <strong>An\u00e1lise de \u00cdndice Livre<\/strong> (por exemplo, GROUP BY na parte principal do \u00edndice) e seleciono \u00edndices compostos ao longo do agrupamento. Quando os resultados interm\u00e9dios se tornam volumosos, uma materializa\u00e7\u00e3o com chaves adequadas escala melhor do que uma \u00fanica mega-jun\u00e7\u00e3o. Mido regularmente as m\u00e9tricas dos handlers e os contadores Created_tmp_* para detetar pontos cr\u00edticos de ordena\u00e7\u00e3o e de tabelas tempor\u00e1rias.<\/p>\n\n<h2>Subconsultas, semi-join e materializa\u00e7\u00e3o<\/h2>\n\n<p>Muitas subconsultas podem ser reformuladas de forma eficiente na fase de prepara\u00e7\u00e3o. As constru\u00e7\u00f5es IN\/EXISTS podem ser substitu\u00eddas por <strong>Semi-Join<\/strong> funcionam com estrat\u00e9gias como a materializa\u00e7\u00e3o ou o LooseScan. Verifico se o otimizador \u00e9 um <strong>derived_merge<\/strong> conseguiu executar: se uma tabela derivada (ou um WITH-CTE) for inserida no plano externo, os seus \u00edndices ficam diretamente dispon\u00edveis. Se isso n\u00e3o for poss\u00edvel, a subconsulta acaba numa tabela tempor\u00e1ria \u2014 nesse caso, se for vi\u00e1vel, atribuo-lhe uma chave (por exemplo, atrav\u00e9s de SELECT DISTINCT\/ORDER BY nas colunas-chave), para que as jun\u00e7\u00f5es n\u00e3o acabem no limbo.<\/p>\n\n<pre><code>-- Exemplo: EXISTS em vez de IN e tabela derivada compat\u00edvel com Merge\nSELECT o.id\nFROM orders o\nWHERE EXISTS (\n  SELECT 1 FROM payments p\n  WHERE p.order_id = o.id AND p.state = 'captured'\n);\n\n-- Deriva\u00e7\u00e3o com chaves \u00fanicas\nWITH paid_orders AS (\n  SELECT DISTINCT order_id\n  FROM payments\n  WHERE state = 'captured'\n)\nSELECT o.*\nFROM orders o\nJOIN paid_orders po ON po.order_id = o.id;\n<\/code><\/pre>\n\n<p>Utilizo o comando EXPLAIN FORMAT=JSON para verificar se <strong>materializado<\/strong> ou <strong>subconsulta dependente<\/strong> foi selecionado e se existem condi\u00e7\u00f5es (<strong>condi\u00e7\u00e3o de pushdown<\/strong>) agir com a devida anteced\u00eancia.<\/p>\n\n<h2>Particionamento e poda<\/h2>\n\n<p>A particionamento n\u00e3o substitui os \u00edndices, mas pode <strong>Volume de dados por acesso<\/strong> reduzir drasticamente. O Optimizer s\u00f3 realiza uma poda correta se o predicado <strong>Chave de parti\u00e7\u00e3o<\/strong> seja inequivocamente identificada e n\u00e3o seja obscurecida por fun\u00e7\u00f5es. Por isso, evito express\u00f5es como DATE(created_at) na condi\u00e7\u00e3o WHERE em tabelas particionadas e, em vez disso, trabalho com limites de intervalo. O EXPLAIN mostra quais as parti\u00e7\u00f5es que s\u00e3o lidas; intervalos muito amplos indicam uma m\u00e1 sele\u00e7\u00e3o de parti\u00e7\u00f5es.<\/p>\n\n<p>Um n\u00famero excessivo de parti\u00e7\u00f5es pequenas aumenta a sobrecarga de planeamento. Por isso, opto por uma granularidade adequada (por exemplo, mensal em vez de di\u00e1ria), mantenho as estat\u00edsticas atualizadas por parti\u00e7\u00e3o (ANALYZE PARTITION) e verifico se os \u00edndices importantes est\u00e3o dispon\u00edveis localmente nas parti\u00e7\u00f5es. Em projetos de migra\u00e7\u00e3o, tenho em conta o impacto na replica\u00e7\u00e3o e na c\u00f3pia de seguran\u00e7a \u2013 ambos influenciam o grau de agressividade com que realizo a parti\u00e7\u00e3o.<\/p>\n\n<h2>Sargability e padr\u00f5es de reescrita<\/h2>\n\n<p>A solu\u00e7\u00e3o mais simples continua a ser <strong>Caix\u00e3o<\/strong> \u2013 Condi\u00e7\u00f5es que permitem a utiliza\u00e7\u00e3o de \u00edndices. Evito fun\u00e7\u00f5es nas colunas na cl\u00e1usula WHERE, reduzo as constantes ao n\u00edvel das colunas e, se necess\u00e1rio, separo as condi\u00e7\u00f5es OR em <strong>UNI\u00c3O TODOS<\/strong>. Para pesquisas LIKE sem \u00e2ncora inicial (\"%foo\"), um \u00edndice BTREE n\u00e3o serve de nada; neste caso, pretendo utilizar a pesquisa de texto completo ou um servi\u00e7o de pesquisa adequado. Para c\u00e1lculos, utilizo <strong>colunas geradas com \u00edndice<\/strong>, para que o otimizador consiga identificar a l\u00f3gica no \u00edndice.<\/p>\n\n<pre><code>-- Anti-padr\u00e3o: fun\u00e7\u00e3o na coluna\nWHERE DATE(created_at) = '2026-08-01'\n-- Melhor: intervalo com valor bruto\nWHERE created_at &gt;= '2026-08-01' AND created_at &lt; &#039;2026-08-02&#039;\n\n-- Anti-padr\u00e3o: o OR impede a utiliza\u00e7\u00e3o do \u00edndice\nWHERE status = &#039;open&#039; OR customer_id = 42\n-- Melhor: duas pesquisas com UNION ALL e um \u00edndice pr\u00f3prio para cada uma\n(SELECT ... WHERE status = &#039;open&#039;)\nUNION ALL\n(SELECT ... WHERE customer_id = 42&#039;);\n<\/code><\/pre>\n\n<p>No que diz respeito aos \u00edndices compostos, considero que a <strong>regra do prefixo \u00e0 esquerda<\/strong> Aplico rigorosamente esta regra, ordenando as colunas por seletividade e de acordo com a ordena\u00e7\u00e3o que ser\u00e1 necess\u00e1ria posteriormente. Se precisar de um ORDER BY descendente, tenho isso em conta no layout do \u00edndice \u2013 assim evito a ordena\u00e7\u00e3o por ficheiros.<\/p>\n\n<h2>Op\u00e7\u00f5es do otimizador e ajuste fino dos custos<\/h2>\n\n<p>Antes de analisar as consultas, verifico <strong>optimizer_switch<\/strong> e mem\u00f3ria tamp\u00e3o. Funcionalidades como <em>mrr<\/em>, <em>batched_key_access<\/em>, <em>index_merge<\/em>, <em>semijoin<\/em>, <em>derived_merge<\/em> ou <em>condi\u00e7\u00e3o_pushdown_para_derivados<\/em> podem ser ajustados por sess\u00e3o. Ativo candidatos de forma seletiva para uma sess\u00e3o de teste, avalio com EXPLAIN ANALYZE e reverto as altera\u00e7\u00f5es se o efeito n\u00e3o for o esperado. O percurso da jun\u00e7\u00e3o beneficia de uma quantidade suficiente de <strong>tamanho_de_jun\u00e7\u00e3o<\/strong>; grandes variedades de <strong>tamanho do buffer de ordena\u00e7\u00e3o<\/strong>. Ao mesmo tempo, mantenho-me atento \u00e0s mem\u00f3rias tamp\u00e3o em rela\u00e7\u00e3o \u00e0 concorr\u00eancia, para que o servidor n\u00e3o entre em modo de troca de mem\u00f3ria sob carga paralela.<\/p>\n\n<p>No que diz respeito aos custos, ajusto, se necess\u00e1rio, os j\u00e1 mencionados <strong>custos_do_otimizador<\/strong> em microssegundos. O meu guia: pequenos passos revers\u00edveis com pontos de medi\u00e7\u00e3o documentados. Utilizo <strong>LAST_QUERY_COST<\/strong> para verificar a plausibilidade e repito as medi\u00e7\u00f5es com valores de par\u00e2metros realistas, uma vez que os planos podem depender fortemente de valores concretos.<\/p>\n\n<h2>Estabilidade do plano, regress\u00f5es e fluxo de trabalho da equipa<\/h2>\n\n<p>Mesmo um bom plano pode ser afetado pelo aumento do volume de dados ou por mudan\u00e7as de vers\u00e3o <strong>tombar<\/strong>. Por isso, garanto-me de ter conhecimento sobre os planos de execu\u00e7\u00e3o: hashes de consultas, JSON do EXPLAIN, excertos do rastreio do otimizador e tempos de execu\u00e7\u00e3o do EXPLAIN ANALYZE. As altera\u00e7\u00f5es aos \u00edndices e as reescritas s\u00e3o submetidas por mim como pull requests, acompanhadas de comprovativos do antes e do depois. Em ambientes de CI\/CD, verifico automaticamente as consultas cr\u00edticas em rela\u00e7\u00e3o a conjuntos de dados representativos. \u00c9 assim que come\u00e7o <strong>Planos de regress\u00e3o<\/strong> cedo.<\/p>\n\n<p>Para casos delicados, considero que <strong>Dicas<\/strong> (FORCE INDEX, STRAIGHT_JOIN, optimizer_switch por consulta) est\u00e3o dispon\u00edveis como \u00faltima op\u00e7\u00e3o, mas utilize-as com modera\u00e7\u00e3o e com prazo de validade. \u00c9 melhor resolver as causas \u2013 estat\u00edsticas, \u00edndices, formula\u00e7\u00e3o. Nas equipas, um guia simples sobre escalabilidade, conce\u00e7\u00e3o de \u00edndices e disciplina de medi\u00e7\u00e3o garante que novas funcionalidades n\u00e3o introduzam, sem que se d\u00ea por isso, problemas de desempenho.<\/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\/08\/mariadb-query-optimizer-7832.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>Resumo: Do plano \u00e0 execu\u00e7\u00e3o<\/h2>\n\n<p>Quem pode utilizar o <strong>Plano<\/strong> Compreender \u00e9 controlar o desempenho. As fases de an\u00e1lise (Parsing), prepara\u00e7\u00e3o (Preparing), otimiza\u00e7\u00e3o (Optimizing) e execu\u00e7\u00e3o (Executing) explicam onde se perde tempo. O modelo de custos baseado no tempo a partir da vers\u00e3o 11.0, as estat\u00edsticas atualizadas e os histogramas tornam as estimativas fi\u00e1veis. Os comandos EXPLAIN, EXPLAIN ANALYZE e o Optimizer Trace proporcionam transpar\u00eancia, que eu traduzo em medidas concretas. Com uma estrat\u00e9gia de indexa\u00e7\u00e3o bem definida, um design claro das consultas e uma infraestrutura adequada, as consultas do MariaDB fornecem respostas sempre r\u00e1pidas.<\/p>","protected":false},"excerpt":{"rendered":"<p>Descubra como funciona internamente o otimizador de consultas do MariaDB, como analisar o plano de execu\u00e7\u00e3o SQL com o EXPLAIN e como implementar t\u00e9cnicas pr\u00e1ticas de otimiza\u00e7\u00e3o de bases de dados \u2013 incluindo dicas para aplica\u00e7\u00f5es web de alto desempenho.<\/p>","protected":false},"author":1,"featured_media":20923,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[781],"tags":[],"class_list":["post-20930","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":"129","_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":"MariaDB Optimizer","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":"20923","footnotes":null,"_links":{"self":[{"href":"https:\/\/webhosting.de\/pt\/wp-json\/wp\/v2\/posts\/20930","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=20930"}],"version-history":[{"count":0,"href":"https:\/\/webhosting.de\/pt\/wp-json\/wp\/v2\/posts\/20930\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/webhosting.de\/pt\/wp-json\/wp\/v2\/media\/20923"}],"wp:attachment":[{"href":"https:\/\/webhosting.de\/pt\/wp-json\/wp\/v2\/media?parent=20930"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/webhosting.de\/pt\/wp-json\/wp\/v2\/categories?post=20930"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/webhosting.de\/pt\/wp-json\/wp\/v2\/tags?post=20930"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}