Seções iMasters
Banco de Dados + CMS + WordPress

O modelo de dados do WordPress

Olá, pessoal. Neste artigo vou
apresentar uma análise do modelo de dados utilizado no WordPress – o CMS
(Content Management System), mais popular nos dias atuais. Além de analisar o
modelo de dados, vou disponibilizar scripts, imagens, e o próprio modelo de
dados em outros formatos para aqueles que precisem saber como os dados são
armazenados no MySQL quando se utiliza o WordPress.

O WordPress pode ser utilizado
basicamente de duas formas: 1) Através do domínio wordpress.com, onde é possível
criar um blog gratuitamente e sem muito conhecimento técnico de seu
funcionamento interno; e 2) Através do download e da instalação do WordPress
disponível no site oficial http://wordpress.org/

Vamos nos concentrar nos detalhes técnicos envolvidos no banco de dados e nosso foco é para aqueles que têm que lidar com este tipo de trabalho, e não para quem apenas usa o WordPress para gerenciar conteúdo. É razoável admitir que a maioria dos usuários não precisa conhecer o modelo de dados devido à facilidade do uso do painel administrativo do WordPress. Porém os administradores, desenvolvedores de plug-ins e quem resolve problemas de desempenho ou integração com o WordPress devem conhecer este modelo bem.

Vejamos o modelo de dados que este CMS utiliza. A Figura 1 apresenta o modelo de dados (isto é, as tabelas e seus tipos de dados) utilizados pelo WordPress 2.9 e modelados na ferramenta de código aberta DBDesigner disponível em diversas plataformas.

Figura 1. modelo de dados do wordpress 2.9 no dbdesigner

Figura 1. Modelo de dados do WordPress 2.9 no DBDesigner

Oficialmente há uma página que contém informações sobre este modelo, inclusive com detalhes das tabelas e suas colunas. Porém esta página apresenta um fraco dicionário de dados sem muitas informações detalhadas a respeito de certas características do modelo como, por exemplo, justificativas a respeito dos tipos de dados. A página oficial que traz a descrição do modelo de dados do WordPress é http://codex.wordpress.org/Database_Description. Aconselho a todos que desejam conhecer mais sobre este modelo visitar esta página regularmente devido às modificações implementadas a cada nova versão do WordPress. Aliás, a figura que contém o modelo de dados desta página oficial não contém a nova tabela wp_commentmeta.

Outro detalhe importante é que durante a instalação do WordPress pode-se escolher qual será o prefixo da tabela, ou seja, o prefixo wp_ é apenas uma sugestão. Um outro detalhe interessante da instalação do WordPress é que não existe um arquivo sql contendo todos os comandos necessários para a criação do banco de dados, ou seja, é preciso fazer uma chamada a um arquivo .php após as configurações de acesso a banco de dados no painel administrativo do WordPress. Devido a isso, neste artigo vou disponibilizar alguns scripts com a estrutura e os comandos de criação do modelo do WordPress 2.9.

A Figura 2 apresenta o mesmo
modelo de dados da Figura 1, porém modelado utilizando a ferramenta livre de
modelagem e administração chamada MySQL Workbench

Figura 2. modelo de dados do wordpress 2.9 no mysql workbench.

Figura 2. Modelo de dados do WordPress 2.9 no MySQL Workbench.

Nota-se que na Figura 2 é possível observar também os índices de cada uma das tabelas. Para fazer o download dos modelos do WordPress 2.9 no DB Designer e no MySQL Workbench basta clicar aqui. O arquivo compactado também contém as imagens no formato png e svg, os scripts sql de criação gerados pelo DBDesigner e pelo comando dump do MySQL, além de arquivos .pdf com as imagens. Estes recursos são ótimos para serem impressos e pendurados na parede, dando aquele toque de decoração geek especial para os ambientes de desenvolvimento.

Antes de começar a análise do modelo é preciso dizer que oficialmente o WordPress só pode ser instalado no MySQL. Isso quer dizer que se a empresa já possui outro banco de dados, como PostgreSQL, SQL Server ou Oracle por exemplo, é preciso configurar um ambiente multi-banco, o que possui implicações para quem administra os servidores. Na página oficial do WordPress há uma descrição dos motivos que levaram a equipe de desenvolvimento do WordPress a escolher apenas o MySQL como banco de dados e também quais são as possíveis abordagens para tornar este CMS mult-banco destacadas com argumentos a favor e contra cada uma das abordagens. De qualquer forma, existem projetos que se propõem a suportar o WordPress no PostgreSQL (http://wordpress-pg.sourceforge.net/ e http://sourceforge.net/projects/postgresqlword/files/
), no SQL Server (http://www.ixalon.net/2008/10/wordpress-and-microsoft-sql-server/ e http://www.forestpointtechnologies.com/blog/wordpress-on-sql-server/)  e em outros bancos de dados (http://wordpress.org/extend/plugins/pdo-for-wordpress/ e http://wordpress.org/extend/plugins/external-database-authentication/).

Mais um pequeno detalhe antes da análise do modelo: o próprio criador do WordPress, Matt Mullenweg, afirmou recentemente no evento CMS Brasil 2009, realizado pelo iMasters, que inicialmente todas as configurações e dados eram armazenadas em arquivos de configuração separadas, seguindo a tradição do ambiente Unix. Conforme o projeto foi crescendo, estas configurações foram inseridas no banco de dados, o que tornou a ferramenta dinâmica o suficiente para se tornar um CMS robusto. Contudo, esta inserção não foi algo muito planejado do ponto de vista formal de modelagem de banco de dados como veremos a seguir.

O primeiro ponto que chama a atenção no modelo do WordPress é a falta de chaves estrangeiras. Este modelo de dados não possui nenhuma chave estrangeira, provavelmente devido ao fato de que ele foi criado utilizando o engine MyISAM do MySQL ao invés do engine InnoDB.

O MySQL apresenta a criação de chaves estrangeiras com o engine InnoDB a partir da versão 3.23.43b. O MySQL já está na versão 6, porém há o famoso problema de compatibilidade com as base legada. Provavelmente escolheu-se o MyISAM por facilidade e por motivos de desempenho, o que NÃO quer dizer que um banco de dados com o InnoDB não possa ser ajustado para ter uma performance aceitável. Sem entrar em uma discussão mais profunda, em geral muitas pessoas advogam que o engine MyISAM possui melhor performance que o InnoDB, porém este último possui suporte a transações, integridade e outros recursos que o MyISAM não possui.

Mais uma vez, sem entrar em detalhes, existem diversas técnicas para otimizar um banco de dados do WordPress como configuração do cache do MySQL, reescrita de consultas, tipagem e outras. Os detalhes destas técnicas ficam como assunto para um outro artigo, pois neste me concentro apenas na análise do modelo, o que também pode afetar positivamente ou negativamente o desempenho

A falta de chaves estrangeiras quer dizer que o relacionamento entre algumas tabelas não é mantido pelo banco de dados e sim pela aplicação. Isso permite que haja dados inconsistentes no banco de dados como, por exemplo, um comentário de um blog que não tem nenhum post associado. Apesar deste cenário ser fictício e ocorrer apenas quando alguém altera os dados diretamente pelo banco de dados e não pelo painel de administração do WordPress, esta possibilidade de inconsistência pode gerar problemas, principalmente quando se fala em migração de dados e segurança.

Aqui temos outra característica da aplicação: caso haja necessidade de se programar algo no WordPress, deve-se utilizar a linguagem PHP e fazer uso de uma camada de abstração de dados implementada pela biblioteca ezSQL, responsável por criar classes que permitem o acesso aos dados. Se o desenvolvedor quiser, ele também pode enviar instruções SQL diretamente para o banco de dados, como estas 13 consultas SQL úteis para quem trabalha com blogs no WordPress.

Outro aspecto que pode afetar muito o desempenho do WordPress é a tipagem de dados. Já abordei este assunto em uma coluna anterior aqui do iMasters chamada Desperdiçando espaço em disco, porém basta dizer que os tipos de dados utilizados neste modelo são demasiadamente exagerados, o que pode gerar vários problemas de desempenho quando a base se torna carregada. Destaque especial vai par o tipo unsigned BIGINT(20) utilizado nas chaves primárias e nos índices: este tipo de dados armazena valores de 0 a 18.446.744.073.709.551.615 ou 18 quintilhões 446 quatrilhões
744 trilhões 73 bilhões 709 milhões 551 mil e 615 ou aproximadamente 10
elevada
à 18 potência
em 20 bytes. Suponho que raramente um blog ou outro tipo de aplicação chegue a este número de posts ou comentários. Isso implica em mais sobrecarga nas páginas de dados e de índices, uma vez que todas as tabelas do modelo contém uma chave primária com o tipo de dados BIGINT(20).

Além da tipagem exagerada, há também redundância de informação: praticamente toda a informação relacionada à data é armazenada em duas colunas com tipos de dados diferentes. Por exemplo, a tabela wp_comments que armazena os comentários dos posts contém as colunas comment_date e comment_date_gmt, ambas do tipo DATETIME. Se o objetivo é armazenar a data, bastaria apenas a coluna que armazena a data no formato GMT. Mais uma vez, provavelmente existem duas colunas devido à compatibilidade com o legado: é possível que inicialmente existisse apenas uma coluna e posteriormente adicionou-se a segunda. Porém remover a primeira coluna faria páginas anteriores do WordPress pararem de funcionar.

Outro aspecto do modelo é a falta de normalização. Isso mesmo, o modelo de dados do WordPress não está normalizado até a terceira forma normal. Isso se deve porque existem colunas que trazem dados agregados e repetidos como, por exemplo, a coluna comment_count da tabela wp_posts. Esta coluna armazena a quantidade de comentários do post, valor este que pode ser calculado contando-se as linhas da tabela wp_comments em uma instrução SQL. O motivo de armazenar esta informação que pode ser derivada do modelo provavelmente é o desempenho. Esta técnica é similar a modelos dimensionais utilizados em sistemas OLAP.

Outro detalhe interessante é que o modelo de dados não possui nenhuma outra integridade de domínio ou stored procedure que faça restrição ao que é inserido no banco. Apesar de isso não ser obrigatório, esta prática abre margem para problemas como SQL Injection onde um usuário malicioso pode tentar invadir o site por meio de caracteres especiais. Além disso, a falta desta integridade pode permitir dados que invalidem a aplicação como, por exemplo, colocar o valor -2 na coluna menu_order  da tabela wp_posts. Há também algumas colunas de tabelas onde o valor NULL é permitido, tornando necessária uma checagem adicional na aplicação. Enquanto alguns podem argumentar que isso é responsabilidade da aplicação, não é raro encontrar bancos de dados com este tipo de integridade de domínio implementada, fornecendo assim mais uma camada de segurança e consistência de dados.

Outro aspecto a ser mencionado no modelo é o armazenamento de arquivo atachado em um post. De acordo com o modelo, os tipos de arquivos são armazenados na coluna post_mine_type da tabela wp_posts, a principal tabela do modelo. Contudo os arquivos em si são colocados em um diretório da instalação do WordPress. Enquanto existem vantagens e desvantagens de se colocar arquivos armazenados internamente no banco de dados, existem também questões de segurança, espaço em disco, acesso concorrente e atualização do conteúdo destes arquivos que ficam fora do banco de dados, gerando assim uma tarefa adicional para o administrador. Esta técnica de armazenar apenas o local de um arquivo no banco de dados ao invés de seu conteúdo é tão comum que foi classificada como um dos database anti-patters, que podem ser vistos nesta apresentação.

Em resumo, pode-se dizer que o modelo do WordPress atende a sua necessidade, porém não é um modelo ideal do ponto de vista da modelagem formal. Em diversas situações, como em uma consultoria de banco de dados recente, tive que efetuar mudanças no modelo de banco de dados visando resolver problemas de desempenho, especialmente em sites cujo volume de acesso é grande. Porém o WordPress ainda é uma aplicação relativamente nova e com o apoio da comunidade pode se tornar cada vez melhor, particularmente em relação ao seu banco de dados.

Um grande abraço e até a próxima.

Mensagem do anunciante:

Já imaginou ter um dia de especialistas em WordPress por conta do seu site? Agora é possível, conheça o Apiki WP One Day. Apiki WP One Day.

Comente também

10 Comentários

É 709 milhões o correto no seu texto heje.

    Mauro Pichiliani

    Olá Fernando.

    Você tem razão. Essa é uma pequena errata do artigo que já pedi para corrigirem. O correto é: 8 quintilhões 446 quatrilhões 744 trilhões 73 bilhões 709 milhões 551 mil e 615.

Vinicius Ianni

Bom artigo, gostei do que foi abordado e coincidentemente se encaixa com algo que pretendo implantar num dos sites que administro, onde será necessária uma personalização e um bom ajuste fino do wordpress e o conteudo deste artigo e dos próximos serão de grande valia.

Sensacional o post !!! Muito bom !!!

Excelente post ajudou a achar muitos pontos de problemas aki (n precisava ser tão polido, pode malhar mesmo a modelagem do negocio, eu mesmo ja sofri com essa coisa ai).
Curti mais ainda os links.

Essa modelo no DBDesigner é grosseiro demais, fica muito estranho, no entanto o que foi gerado no MySQL Workbench é mais claro, deixando a parte do software utilizado de lado, vamos a alguns detalhes como: o wordpress veio crescendo junto com a era web2.0, o banco de dados dele teve que se adaptar a isso, por isso não existe a parte do innodb, pois na maioria dos servidores por aí, somente MyISAN está disponível, e claro foi pensado no desepenho mesmo quando optado por fazer os “relacinamentos”na maneira que está, a questão do BIGINT(20), se você ler os changelog. vem da necessidade que as tabelas wp_usermeta e wp_sitemeta tem de crescer e manter os indices se “relacionando”, pois cada usuário cria suas informações lá e gera até umas 100 informações diferentes, levando em conta que se use replicação de dados, você teria a contagem das chaves em 10 em 10, por exemplo,1…11…21…31, cada usuário com 100 informações, ocupariam 1000 numeros em um dos servidores, entao os seus quintilhoes reduziriam bastante, talvez em algumas tabelas isso seria um exagero mesmo, mas talvez eles devam ter usado apenas para igualar todas elas, a parte do comment_count, também tenho uma observação, aqui temos um wordpress com 84000 tabelas, e se formos contar os comentários e posts contando os registros, geramos concorrência com quem está postando, então no meu ponto isso é uma coisa boa e não ruim. Gostei do seu artigo, porém deveria ter equilibrado a parte ruim e boa do negócio, ficou uma visão meio distorcida talvez, e uma dica simples de desempenho em wordpress, em vez de alterar o DB, seria remover o “true” no script de conexão que a torna persistente.
Abraços

Rodrigo Pacheco

Post muito bacana!

Porém acho que um pouco de imparcialidade cairia bem… :-)

Bruno Costa

Gostei do post. Concordo totalmente que o modelo com MySQL Workbench é mais inteligente

Leandro Vieira

Ótimo post Mauro.

É sempre de grande valia nos deparar com artigos assim aqui no iMasters.

Keep walking!

Diego

Atualmente desenvolvo uma página customizada que será implementada as páginas no banco através do Visual Studio C#. Estou estudando as tabelas a fundo e percebi que é possível criar página através do bando de dados.

Qual a sua opinião?