Tarrn: Neukunden per SQL Abfrage

Hallo zusammen,

grundsätzlich habe ich 2 Lösungen für den Weg - es geht darum, dass ich die Anzahl der Kunden in einem Monat brauche, deren Email (ja nicht astrein, mir bewusst, aber aufgrund der Datenbank Modellierung nicht anders möglich) vorher nicht in der Tabelle auftaucht.

Mein Problem ist eigentlich, dass mir die Datenbank bei beiden Abfragen immer ins Timeout geht.

Erster Ansatz:

select count(email)
 from 
(select email from x.tOrder where  Created_At > "2017-01-01 00:00:00" and Created_At < "2017-01-31 23:59:59"and email not in (select email from x.tOrder where Created_At < "2016-12-31 00:00:00")
group by email
having count(email) = 1) t 

Zweiter Ansatz

select monthOrders.email from
(
/* orders */
select email from x.tOrder 
where  Created_At > "2017-01-01 00:00:00" and Created_At < "2017-01-31 23:59:59"
) monthOrders
left join
(
/* old orders */
select email from x.tOrder 
where Created_At < "2016-12-31 23:59:59" and AxaptaId != "PAYMENT_PENDING" 
) beforeOrders
on monthOrders.email=beforeOrders.email
where beforeOrders.email is null

Jemand eine stabilere / schnellere Idee für mich?

  1. aber aufgrund der Datenbank Modellierung nicht anders möglich) vorher nicht in der Tabelle auftaucht.

    Die Logik wäre: Eine Abfrage bez. Kunden die in einem bestimmten Zeitraum hinzugekommen sind. Was einen Index ermöglicht und damit eine Abfrageoptimierung. MfG

    1. Problematik ist hierbei nur, dass ich dazu einen Cronjob einrichten müsste, der erstmals 8 Stunden durchläuft und das geht gerade aus diversen Gründen nicht :/

      1. Problematik ist hierbei nur, dass ich dazu einen Cronjob einrichten müsste, der erstmals 8 Stunden durchläuft und das geht gerade aus diversen Gründen nicht :/

        Des Weiteren: Eine Emailadresse die in bisherigen Bestellungen nicht benutzt wurde, ist kein Kriterium für einen Neukunden. Idealerweise ist eine Kundenverwaltung ohnehin von Bestellungen sauber getrennt. Unter Beachtung der DSGVO versteht sich.

        MfG

  2. Tach!

    Jemand eine stabilere / schnellere Idee für mich?

    Es ist meistens schwierig, eine Lösung zu finden, ohne die Tabellenstruktur zu kennen. Was sagt denn der Ausführungsplan? Bei MySQL mit vorangestelltem EXPLAIN zu bekommen. Werden die vorhandenen Indexe verwendet? Sind letztere überhaupt passend für die Abfrage gesetzt? Nicht kriegsentscheidend dürfte jedenfalls sein, BETWEEN für von-bis-Abfragen zu verwenden.

    dedlfix.

  3. 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