You can try several rewrites and compare execution plan and times.
Using 2 EXISTS
subqueries (one for each word to be checked):
SELECT t.threadid
FROM thread AS t
WHERE EXISTS
( SELECT 1
FROM post AS p
JOIN postindex AS pi
ON pi.postid = p.postid
JOIN word AS w
ON pi.wordid = w.wordid
WHERE w.title = 'word1'
AND t.threadid = p.threadid
)
AND EXISTS
( SELECT 1
FROM post AS p
JOIN postindex AS pi
ON pi.postid = p.postid
JOIN word AS w
ON pi.wordid = w.wordid
WHERE w.title = 'word2'
AND t.threadid = p.threadid
) ;
Using one EXISTS
subquery:
SELECT t.threadid
FROM thread AS t
WHERE EXISTS
( SELECT 1
FROM post AS p1
JOIN postindex AS pi1
ON pi1.postid = p1.postid
JOIN word AS w1
ON w1.wordid = pi1.wordid
AND w1.title = 'word1'
JOIN post AS p2
ON p2.threadid = p1.threadid
JOIN postindex AS pi2
ON pi2.postid = p2.postid
JOIN word AS w2
ON w2.wordid = pi2.wordid
AND w2.title = 'word2'
WHERE t.threadid = p1.threadid
AND t.threadid = p2.threadid
) ;
A single query with many joins and GROUP BY
only to remove the duplicate threadid
:
SELECT t.threadid
FROM thread AS t
JOIN post AS p1
ON p1.threadid = t.threadid
JOIN postindex AS pi1
ON pi1.postid = p1.postid
JOIN word AS w1
ON w1.wordid = pi1.wordid
AND w1.title = 'word1'
JOIN post AS p2
ON p1.threadid = t.threadid
JOIN postindex AS pi2
ON pi2.postid = p2.postid
JOIN word AS w2
ON w2.wordid = pi2.wordid
AND w2.title = 'word2'
WHERE p1.threadid = p2.threadid -- this line is redundant
GROUP BY t.threadid ;