Seit vielen Jahren programmiere ich ehrenamtlich für mehrere gemeinnützige Jugendverbände eine Freizeitdatenbank auf Basis eines SQL Servers als Backend und MS Access als Frontend. Das Datenmodell ist so weit wie möglich normalisiert, so dass es u.a. Tabellen
zu
Personen
Freizeiten
Anmeldungen zu Freizeiten
Zusatzoptionen zu Freizeiten
Gewählte Zusatzoption einer Anmeldung
Buchungen
gibt. In den verschiedenen Menüs sind häufig auch berechnete Eckdaten enthalten. So gibt es im Freizeitmenü einen Reiter mit der Auflistung der Teilnehmer. Darunter sind dann statistische Eckdaten aufgeführt: Gesamtzahl, männliche, weibliche Teilnehmer,
Begleitpersonen, etc.
Auch beim Reiter „Buchhaltung“ finden sich statistische Eckdaten, die man für einen schnellen Eindruck braucht ohne eigens detaillierte Berichte aufrufen zu müssen: Teilnehmergebühren und Stornogebühren (SOLL), bezahlte Gebühren (IST), Differenz von SOLL
und IST, etc.
Die Dauer zum Aufruf des jeweiligen Menüs in Access ist gerade noch OK – ich würde mir aber eine deutlich höhere Performance wünschen. In den letzten Jahren habe ich daher einen Abstecher zur „In-Memory-Technologie“ gemacht. Das hat tatsächlich einiges an
Geschwindigkeit gebracht – war aber mit so vielen Nachteilen und Problemen verbunden, dass ich mich letztlich dann doch wieder davon verabschiedet habe.
Ein wesentlicher Punkt war für mich auch die Optimierung der Indices und Abfragen. Hier kann man sicher auch noch etwas rausholen – aus den relevanten Fachbüchern und Internettipps habe ich aber schon vieles umgesetzt und ausprobiert.
Ein Gedanke, der mich schon länger umtreibt und für den ich mit diesem Post eine „Best-Practice“-Lösung suche ist, ob die statistischen Eckdaten nicht schon vorab in irgendeiner Form berechnet werden können und dann beim Abruf eines Menüs viel schneller
zur Verfügung stehen. Am Beispiel der Teilnehmerzahl kann diese für eine Freizeit eine längere Zeit konstant bleiben (z.B. weil die maximale Teilnehmerzahl sowieso schon erreicht ist) – trotzdem wird das Menü für die Freizeit X-fach aufgerufen.
Meine Suche hat mich jetzt zu indizierten Sichten geführt. Rein vom beschriebenen Rahmen hätte ich gemeint, dass es genau das ist, was ich suche – Berechnungen können damit „materialisiert“ werden. In meiner Vorstellung ist das wie eine Tabelle und ich muss
mich um nichts kümmern. Leider gibt es für diese Sichten keine „OUTER JOINS“, weshalb ich faktisch für jede Unterscheidung eines berechneten Wertes eine eigene Sicht brauche.
CREATE VIEW
[dbo].[IS_Freizeiten_Anzahl_TN_M]
WITH
SCHEMABINDING
AS
SELECT FZ_ID, COUNT_BIG(*) AS
Anzahl_TN_M
FROM dbo.PersFZ PFZ INNER JOIN dbo.Personen
P ON PFZ.Pers_ID = P.Pers_ID
WHERE PersFZ_Warteliste = 0 AND PersFZ_Absage = 0 AND PersFZ_Stornierung =
0 AND PersFZ_Status_Person >= 100 AND PersFZ_Status_Person < 200 AND Pers_Geschlecht = 10
GROUP BY FZ_ID
GO
SET ARITHABORT ON
SET CONCAT_NULL_YIELDS_NULL ON
SET QUOTED_IDENTIFIER ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
SET NUMERIC_ROUNDABORT OFF
GO
/****** Object:
Index [IX_FZ_ID] Script Date:
28.05.2020 21:59:42 ******/
CREATE UNIQUE CLUSTERED INDEX [IX_FZ_ID] ON [dbo].[IS_Freizeiten_Anzahl_TN_M]
(
[FZ_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
Was mich etwas irritiert ist die Tatsache, dass beim Aufruf der Beispielsicht die Datensätze nicht etwa nach der FZ_ID sortiert sind – obwohl die ID als UNIQUE CLUSTERED INDEX gesetzt ist.
Dann braucht die übergreifende Sicht, in der ich wieder die verschiedenen Einzelwerte der indizierten Sichten zusammenfasse zum Aufruf doch recht lange. Schaue ich mir den Ausführungsplan an, so sehe ich, dass z.B. die Bestimmung des Geschlechtes u.ä. Rechenzeit
in Anspruch nehmen. Dabei enthält die zusammenfassende Sicht nur indizierte Sichten nach dem oben aufgezeigten Schema. Ich hätte erwartet, dass auf die bereits berechneten Werte zurückgegriffen wird.
Jetzt bin ich etwas ratlos, was eine bessere Alternative wäre. Ist es „Best Practice“, dass man eine eigene echte Tabelle mit fertig berechneten statistischen Werten erstellt? Nur müsste ich dann überall Trigger setzen, damit jede kleine Änderung dort mitgezogen
wird.
Oder setzt man so etwas mit temporären Tabellen um?