(enligt anvisningarna lägger jag en del av min kommentar i ett svar eftersom det löste problemet)
Konvertera EXISTS-uttrycken till IN-uttryck.
Detta fungerar bättre i det här fallet eftersom frågan nu effektivt utvärderas "inifrån och ut" med början med den fråga som innehåller din mest begränsande faktor:söksökningen i fulltext. Den frågan kommer att returnera en liten uppsättning rader som kan slås upp direkt mot primärnyckeln för den yttre frågan (WHERE x in (SELECT X...)) i motsats till att anropa den "inre" frågan en gång per värde på den yttre frågan (eller för alla värden i ditt ursprungliga fall, om jag läser det rätt). EXISTS-metoden här resulterar i Nested Loops (en utvärdering av en fråga för varje värde i en annan) kontra IN-metoden som använder Hash Joins (en mycket effektivare exekveringsmetod i många, om inte de flesta, fall.
Lägg märke till att med EXISTS-metoden finns det fyra kapslade loopar som körs med varje gång minst 3 000 gånger. Den kostnaden ökar. Även om det inte är en direkt jämförelse, kan du behandla kapslade loopar som du skulle göra FÖR loopar i applikationskoden:varje gång du anropar en inre loop går din big-O-uppskattning upp en storleksordning:O(n) till O(n^ 2) till O(n^3), etc.
Hash Join är mer som en karta, där två arrayer stegas igenom samtidigt och en operation utförs på båda. Detta är ungefär linjärt (O(n)). Tänk på att dessa kapslades som additiv så att de skulle gå O(n) till O(2n) till O(3n), etc.
Ja, ja, jag vet att det inte är riktigt samma sak, men poängen är att att ha flera kapslade slingor vanligtvis indikerar en långsam frågeplan och att jämföra de två big-O-stilarna gör det lättare att känna igen, tror jag.
Kapslade loopar och EXISTS är inte onda i sig, men för de flesta fall där det finns ett basfiltervillkor som i slutändan påverkar allt (till exempel fulltextsökningen i frågan), ett IN-uttryck (eller, i vissa en korrekt JOIN) ger en mycket effektivare plan.