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
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.
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.