MySQL Serve aiuto per la definizione di SQL per rimuovere le righe indesiderate

Quindi il progetto sta facendo un semplice CMS in PHP. Hai post, categorie e tag. Gestirà milioni di post in un database, milioni di tag e categorie.

Il problema: in modo ottimale, vuoi essere in grado di select 30 post che devono essere inclusi nelle categorie 5 e 1 e 2. Vuoi farlo nel minor numero ansible di query …

termRelations contiene il post ID e il term ID, con termTypeId che distingue tra le tabelle cats e tag.
gatti contiene il termine ID e informazioni sulla categoria (nome, lumaca, ecc.)
i tag contengono il termine ID e le informazioni sui tag (Nome, slug, ecc.)

i gatti e i tag sono tabelle separate in modo da velocizzare la generazione di un elenco di categorie / per definirli in modo più separato.

SELECT DISTINCT * FROM posts LEFT JOIN termRelations ON ( posts.id = termRelations.postId ) LEFT JOIN cats ON ( termRelations.termId = cats.id AND termRelations.termTypeId = 1 ) LEFT JOIN tags ON ( termRelations.termId = tags.id AND termRelations.termTypeId = 0 ) WHERE cats.id =5 OR tags.id =2 OR tags.id =1 LIMIT 0 , 30 

In questo caso restituisce 3 righe per un post, i primi due con campi tag aggiunti, l'ultimo con i campi categoria.

Non ho bisogno di queste informazioni per l'uso (come sembra imansible quando si tratta di più tag o categorie in una row. Forse no?), Ho solo bisogno di afferrare post sotto questi tre termini. Tuttavia, se potessi get informazioni su categorie e tag con una query che sarebbe ottimale.

Grazie. Questo sta fottendo il mio cervello. Se sto facendo qualcosa di sbagliato e tu sai un modo più efficiente per farlo, sarei felice di ri strutturare il database.

DISTINCT funziona su tutte le colonne in SELECT così hai SELEZIONA tutto ciò che restituirà each row distinta e non solo i distinti messaggi. Per aggirare questo, basta SELEZIONARE i dati dalla tabella dei post e quindi DISTINCT, ovvero

 SELECT DISTINCT posts.* 

Ma hai anche detto che ti piacerebbe ricevere informazioni sui post e sui gatti, se ansible. Un modo per farlo e mantenere una row per post è utilizzare GROUP_CONCAT in modo che la tua query possa finire in qualcosa del genere.

 SELECT posts.*, GROUP_CONCAT(cats.id SEPARATOR ',') as catsList, GROUP_CONCAT(tags.id SEPARATOR ',') as tagsList FROM posts INNER JOIN termRelations ON ( posts.id = termRelations.postId ) LEFT JOIN cats ON ( termRelations.termId = cats.id AND termRelations.termTypeId = 1 AND cats.id =5 ) LEFT JOIN tags ON ( termRelations.termId = tags.id AND termRelations.termTypeId = 0 AND (tags.id =2 OR tags.id =1) ) GROUP BY posts.id LIMIT 0 , 30 

Ho apportto un paio di altre modifiche alla tua query originale, come la modifica del primo join in un JOIN INTERNO e l'aggiunta dei filtri gatti / tag alle condizioni JOIN per le tabelle pertinenti.

ps quando dici di avere tabelle separate per gatti e tag per accelerare la creazione di liste, potresti scoprire che una tabella indicizzata correttamente sarebbe altrettanto veloce e semplificerebbe anche il tuo codice.