Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Como implementar o sistema de marcação semelhante ao SO em php/mysql?


Antes de entrarmos na otimização prematura modo, pode ser útil examinar o seguinte modelo de consulta. Se nada mais, isso poderia ser usado como uma linha de base contra a qual a eficácia de possíveis otimizações pode ser medida.
SELECT T.Tagid, TagInfo.TagName,  COUNT(*)
FROM Items I
JOIN Tags TagInfo ON TagInfo.TagId = T.TagId
JOIN ItemTagMap T  ON I.ItemId = T.ItemId 
--JOIN ItemTagMap T1 ON I.ItemId = T1.ItemId
WHERE I.ItemId IN
  (
      SELECT ItemId 
      FROM Items
      WHERE   -- Some typical initial search criteria
         Title LIKE 'Bug Report%'   -- Or some fulltext filter instead...
         AND  ItemDate > '02/22/2008'
         AND  Status = 'C'
  )
--AND T1.TagId = 'MySql'
GROUP BY T.TagId, TagInfo.TagName
ORDER BY COUNT(*) DESC

A subconsulta é a "consulta de condução", ou seja, aquela que corresponde aos critérios iniciais do usuário final. (veja abaixo para detalhes sobre como esta consulta, exigida várias vezes, pode caber em um fluxo geral otimizado) Comentado é o JOIN em T1 (e possivelmente T2, T3, quando várias tags são selecionadas) e, com a cláusula WHERE, o associado critério. Eles são necessários quando o usuário seleciona uma determinada tag, seja como parte da pesquisa inicial ou por refinamento. (Pode ser mais eficiente colocar essas junções e cláusulas where dentro da subconsulta; mais sobre isso abaixo)

Discussão... A "consulta de condução", ou uma variação dela, é necessária para dois propósitos distintos:
  • 1 para fornecer o completo lista de ItemId que é necessário para enumerar todas as tags associadas.

  • 2 para fornecer os primeiros N valores de ItemId (N sendo o tamanho da página de exibição), com a finalidade de pesquisar informações de detalhes do item na tabela de itens.


Observe que a lista completa não precisa ser classificada (ou pode se beneficiar da classificação em uma ordem diferente), sendo que a segunda lista precisa ser classificada com base na escolha do usuário (digamos, por Data, decrescente ou por Título, em ordem alfabética crescente ). Observe também que, se houver alguma ordem de classificação necessária, o custo da consulta implicará em lidar com a lista completa (tímido de otimização ímpar pelo próprio SQL e/ou alguma desnormalização, o SQL precisa "ver" os últimos registros dessa lista , caso pertençam ao topo, por ordenação).

Este último fato, é a favor de ter a mesma consulta para ambos os propósitos, a lista correspondente pode ser armazenada em uma tabela temporária. O fluxo geral seria pesquisar rapidamente os principais registros de N Item com seus detalhes e devolvê-los ao aplicativo imediatamente. O aplicativo pode então obter ajax-fashion a lista de Tags para refinamentos. Esta lista seria produzida com uma consulta semelhante à anterior, onde a subconsulta é substituída por um "select * from temporáriaTable". As chances são boas de que o otimizador SQL decida classificar essa lista (em alguns casos), vamos deixá-lo fazer isso, em vez de adivinhar e classificá-la explicitamente.


Um outro ponto a ser considerado é talvez trazer a(s) junção(ões) na tabela ItemTagMap dentro da "consulta de condução" em vez de como mostrado acima. Provavelmente é melhor fazê-lo, tanto pelo desempenho quanto porque produzirá a lista certa para o propósito nº 2 (exibição de uma página de itens).

A consulta/fluxo descrito acima provavelmente será dimensionada muito bem, mesmo em hardware relativamente modesto; tentativamente em mais de 1/2 milhão de itens, com pesquisas sustentadas de usuários talvez até 10 por segundo. Um dos fatores-chave seria a seletividade dos critérios de busca inicial.

Ideias de otimização
  • [Dependendo dos casos de pesquisa típicos e das estatísticas de dados] pode fazer sentido desnormalizar trazendo (na verdade duplicando) alguns dos campos de Itens para a tabela ItemTagMap. Campos curtos em particular podem ser 'bem-vindos' lá.
  • À medida que os dados crescem em mais de um milhão de itens, podemos explorar a correlação normalmente forte de algumas tags (ex:em SO, PHP geralmente vem com MySql, btw muitas vezes sem um bom motivo...), com vários truques. Por exemplo, a introdução de TagIds "multi-Tag" pode tornar a lógica de entrada um pouco mais complicada, mas também pode reduzir significativamente o tamanho do mapa.


-- 'basta! --
Arquitetura e otimizações apropriadas devem ser selecionadas à luz dos requisitos reais e do perfil estatístico de dados efetivo...