Rolf B: Extreme Performance-Unterschiede zwischen MariaDB und MySQL?

Beitrag lesen

Hallo Felix,

so langsam wird das Thema unübersichtlich...

Soweit in der Query erkennbar, hast Du also einmal die users mit der Spezialisierung staff, und zum anderen die people mit Spezialisierung students, parents und guardians - aber auch die Lehrer. Ist also users eine Spezialisierung von people? Demnach ist also "student", "parent", "guardian" oder "teacher" eine Rolle, die ein Mensch aus people haben kann, und Rollen finden sind typischerweise in m:n Beziehungstabellen wieder. Dein Modell sieht da richtig aus. Was mir quer sitzt, ist users. Zur Zeit sind nur Lehrer User, aber Du willst ja erweitern können. Demnach ist potenziell jeder in people ein User, und der Login gehört dorthin. Es sei denn, du definierst "user" als weitere Rolle, die ein Mensch haben kann - aber da wäre ich pragmatisch.

Anderer Punkt. Ich verstehe Dich so, dass Deine Exists Abfrage die Aufgabe hat, bei Nichtadmins die Berechtigung zu begrenzen. Lehrer sehen die Nachschreibeliste nur für die Kurse, die sie unterrichten. Und Admins sehen alles. In dem Fall ist es aber doch so, dass Du den ganzen Exists-Rattenschwanz nur für eine Lehrer-Query brauchst, und für eine Admin-Query gar nicht (weil es doch zu erwarten ist, dass für jeden Kurs, in dem nachgeschrieben wird, einen Lehrer gibt).

Wenn also mit 1=1 tricksen, dann so (direkte Werteinjektion ins SQL angenommen):

AND (1=$admin OR EXISTS(SELECT ....))

Die Klammern sind wichtig. Siehe nächsten Absatz. Effizienter sollte es aber sein, den AND EXISTS Rattenschwanz nur für Lehrer-Queries ans SQL zu hängen und für Admins komplett wegzulassen. Den 1=1 Trick macht man eigentlich nur, wenn man auf statisches SQL angewiesen ist. Das ist bei PHP nicht der Fall.

Deine Implementierung des 1=1 Tricks scheint mir ohnehin falsch. AND bindet stärker als OR, d.h. für Admins bist Du im EXISTS komplett ohne WHERE Bedingung unterwegs.

Du könntest für Lehrerabfragen auch zunächst einmal den shorthand-Wert des betreffenden Lehrers ermitteln und den als Parameterwert in die Query geben, das eliminiert 2 JOINs. Trotzdem musst Du wieder mit dem SELECT MAX ran, weil ja lessons wie courses den Schedule benutzen. Und das k*tzt mich so richtig an.

Das Grundgerüst der Query ist doch: Ein Schüler S schreibt am Termin X (alt_exam) im Fach Y (course) eine Nachprüfung. Die Beziehung zwischen den dreien wird durch alt_bookings repräsentiert. Am Kurs hängt das Stundenplandatum, ab dem dieser Kurs so gehalten wird. Und das sollte genau einer sein. Das hatte ich schonmal im Zusammenhang mit DISTINCT angesprochen, und du meintest, der Kursname wäre mehrfach da - aber doch nicht zu einem schedule-Datum, oder?

Deswegen sollte man mit dieser Query doch pro Nachprüfungstermin den dort nachgeprüften Kurs bekommen (einmal pro Schüler).

SELECT x.alt_exam, x.date, b.student, p.*, s.form, c.subject
FROM alt_exams X
     JOIN alt_bookings B ON X.alt_exam = B.alt_exam
     JOIN courses C ON C.course_name = B.course_name 
                   AND C.schedule = (SELECT MAX(c2.schedule) FROM courses c2 
                                     WHERE c2.schedule <= x.date)
     JOIN students s ON S.student = B.student
     JOIN people p ON ...

Bis auf Rechteprüfung und Lehrerliste sollte das vollständig und richtig sein. Interessant ist, dass wir jetzt den schedule zum Kurs in der Ergebnismenge haben (wenn auch nicht anzeigen). Du kannst also c.schedule als Input für den Subselect mit dem GROUP_CONCAT verwenden und brauchst da keinen neuen SELECT MAX. Das gleiche gilt für die Rechteprüfung, du kannst auch dort die Lessons mit c.schedule heraussuchen, ohne einen neuen SELECT MAX zu machen.

Rolf

--
sumpsi - posui - clusi