2017-06-08 4 views
0

Hier ist meine Tabellenstruktur:Wie kann ich alle Beiträge auswählen, die bestimmte Tags haben?

// posts 
+----+-----------+---------------------+-------------+ 
| id | title |  body   | keywords | 
+----+-----------+---------------------+-------------+ 
| 1 | title1 | Something here  | php,oop  | 
| 2 | title2 | Something else  | html,css,js | 
+----+-----------+---------------------+-------------+ 

// tags 
+----+----------+ 
| id | name | 
+----+----------+ 
| 1 | php  | 
| 2 | oop  | 
| 3 | html  | 
| 4 | css  | 
| 5 | js  | 
+----+----------+ 

// pivot 
+---------+--------+ 
| post_id | tag_id | 
+---------+--------+ 
| 1  | 1  | 
| 1  | 2  | 
| 2  | 3  | 
| 2  | 4  | 
| 2  | 5  | 
+---------+--------+ 

Ok gut, ich habe zwei Tags (php und html) und ich brauche alle Beiträge mit ihnen markiert auszuwählen. Wie kann ich das machen?

Derzeit verwende ich REGEXP und wählen Sie einfach, was ich so wollen:

SELECT * FROM posts WHERE keywords REGEXP 'php|html'; 

sehen? Ich benutze nicht einmal 1 join. Heutzutage ist mein Dataset groß und meine Abfrage dauert eine Weile, bis sie ausgeführt wird. Ich denke, ich muss ein relationales Feature wie join verwenden. Ich bin mir jedoch nicht sicher, ob es besser wäre als meine aktuelle Anfrage.

Wie auch immer, weiß jemand, wie kann ich das erwartete Ergebnis schneller erhalten?

+1

sollten Sie normalisieren Sie Daten (Schlüsselwörter Inhalt) in der richtigen verwandten Tabelle – scaisEdge

+0

In Posts-Tabelle sollte Spalte mit Tags IDs und dann können Sie aus Posts Tabelle auswählen. – OsamaKhalid

+0

@scaisEdge Wie genau meinst du? Ich würde angesprochen werden, wenn Sie eine Antwort schreiben und Ihr vorgeschlagenes Datenbankdesign erklären. –

Antwort

1

Reguläre Ausdrücke können langsam verarbeitet werden. LIKE verwendet, wird wahrscheinlich eine bessere Reaktionszeiten geben:

SELECT * 
FROM posts 
WHERE (keywords LIKE '%php%' OR keywords LIKE '%html%') 

Die Abfrage auf den normalisierten Tabellen basieren würde:

SELECT  posts.id, posts.title, posts.body, posts.keywords 
FROM  posts 
INNER JOIN pivot ON pivot.post_id = posts.id 
INNER JOIN tags ON tags.id = pivot.tag_id 
WHERE  tags.name IN ('html', 'php') 
GROUP BY posts.id 

Für eine optimale Geschwindigkeit, die Sie, dass die id Felder als Primärschlüssel deklariert sind, müssen sicherstellen, und dass Sie Indizes auf:

tags(name) 
pivot(tag_id) 

Dennoch wird dies nicht schneller als die aktuelle Lösung, wenn ein wesentlicher Teil aller Posts erfüllen die Bedingung: Es könnte durchaus langsamer sein. Wenn jedoch beispielsweise weniger als 1% der Posts die Bedingung erfüllen, wird dies wahrscheinlich eine bessere Leistung bringen, da der Ausführungsplan im Prinzip keinen Scan der gesamten Posts-Tabelle enthalten muss.

+0

Können Sie mir bitte sagen, was 'GROUP BY' in Ihrer zweiten Anfrage tut? Es scheint mir nutzlos. Was passiert, wenn ich es entferne? Ich habe bemerkt, dass ich '=' anstelle von 'IN' in der Realität verwendet habe. –

+1

Die 'group by' wird verwendet, um Wiederholungen desselben Posts in der Ergebnismenge zu vermeiden. Dies kann passieren, wenn ein Beitrag zwei übereinstimmende Einträge in der Pivot-Tabelle hat (eine für "html" und eine für "php"). Wenn Sie 'in' nicht verwenden und nur mit' = 'auf einen Wert vergleichen, müssen Sie natürlich nicht gruppieren. Aber Ihr Beispiel in der Frage erwähnt zwei Tags. – trincot

1

Sie haben bereits ein normalisiertes Design mit einer Beziehung von vielen zu vielen. Die Spalte keywords muss in der posts-Tabelle nicht vorhanden sein, da der Pivot bereits dasselbe erstellt.

Sie müssen nur die Verbindung ordnungsgemäß durchführen. Versuchen Sie dies:

SELECT posts.id 
    FROM posts 
LEFT OUTER JOIN pivot 
    ON posts.id = pivot.post_id 
LEFT OUTER JOIN tags 
    ON pivot.tag_id = tags.id 
WHERE tags.name = "php" or tags.name = "html" 
GROUP BY posts.id; 

Dies wird Ihnen alle IDs der Beiträge mit den Tags geben.

+0

Danke .. upvote –

Verwandte Themen