Hallo Tarn,
ich würde eine Nesting-Stufe weniger machen, du willst ja nicht nur zählen sondern auch wissen wer das ist. Das hat aber keinen Einfluss auf Performance, würde ich vermuten.
Die Grenz-Datümer habe ich mal als Query-Parameter umgeschrieben, damit klar ist, wo exakt der gleiche Wert stehen muss. Deine Query würde nämlich die Kunden als Neukunden behandeln, die sich am 31.12.2017 registriert hatten.
Ich würde statt der IN Abfrage auf EXISTS wechseln, und die Mail-Adresse in die WHERE Bedingung verlegen. Dann kannst Du einen Index mit den Spalten (email, Created_At) auf die Bestellungen legen - das wäre ohnehin nützlich damit man einfach alle Bestellungen eines Kunden findet (besser noch wäre eine separate Kundentabelle, weil Kunden und Bestellungen eigentlich eine 1:N Beziehung haben). Ohne Index wird es - bei einer hinreichend großen Table, langsam bleiben.
Also so:
select email
from x.tOrder o1
where Created_At >= :FromDat and Created_At < :ToDat
and not exists (select email
from x.tOrder o2
where o1.email=o2.email and Created_At < :FromDat)
Mit dem genannten Index sollte der SQL Optimizer daraus einen Indexscan machen, um die Sätze zu finden die Created_At im FromDat-ToDat Zeitfenster haben. Für die EXISTS Abfrage kann er dann mit Index-Seek weitermachen, ohne auf die Table-Daten zugreifen zu müssen und dann per Indexscan prüfen, ob ein Satz existiert der älter ist als FromDat. Wenn Du den Index so baust, dass Created_At darin absteigend sortiert ist, müsste er das in den meisten Fällen mit einem einzigen Seek erledigen können, ohne scannen zu müssen.
Mach mal den Index, probier's aus und lass dir den EXPLAIN zur Query anzeigen. Das ist ohnehin immer der erste Schritt bei der Abfrageoptimierung.
Rolf
sumpsi - posui - clusi