Indizien erstellen | Performance Probleme

domeetr

Benutzer
Beiträge
5
Hallo zusammen,

leider habe ich momentan einige Probleme bzgl. Performance, weshalb ich auf Hilfe dritter angewiesen bin. Vielleicht kennt sich hier der ein oder andere gut bis sehr gut damit aus und kann mir Unterstützung geben.

Kurz zur Umgebung:
Ich habe eine MSSQL-Datenbank. In dieser Datenbank habe ich einige Tabellen. Die meisten dieser Tabellen sind nicht fortlaufend - Einmal täglich bügelt der eine Momentaufnahme rüber von der Hauptdatenbank (DB von einer Anwendung). 3 der Tabellen sind jedoch fortlaufend, weshalb ein Skript von meinem Kollegen geschrieben wurde, das die Daten jeden morgen um eine bestimmte Uhrzeit rüberkopiert (die alten jedoch nicht wie bei der Momentaufnahme löscht).

Datenbank: Sendungsmanger
Tabellen: 37 Tabellen
Zweck der Datenbank: Eine, über PHP angesteuerte, Weboberfläche, wo Analysen, Auswertungen und Übersichten dargestellt werden.

Für die meisten dieser Analysen brauche ich die selben Daten, weshalb ich eine Sicht geschrieben habe die wie folgt aussieht:

Code:
SELECT        dbo.Zustellorganisation.strBez, dbo.Zustellorganisation.strUPOC AS ZustellOrgUPOC, dbo.SendungFormat.strBezeichnung AS Sendungsformat, dbo.Bezirk.strBezeichnung AS Bezirk, dbo.KundeKostenstelleView.strKundeNr,
                         dbo.KundeKostenstelleView.strKundeUPOC, dbo.KundeKostenstelleView.fKundeAktiv, dbo.KundeKostenstelleView.strKundename1, dbo.KundeKostenstelleView.strKundename2, dbo.KundeKostenstelleView.strKundeStrasse,
                         dbo.KundeKostenstelleView.strKundeHausNr, dbo.KundeKostenstelleView.strKundePlz, dbo.KundeKostenstelleView.strKundeOrt, dbo.KundeKostenstelleView.lKsKKSID, dbo.KundeKostenstelleView.strKsUPOC,
                         dbo.KundeKostenstelleView.fKostenstelleAktiv, dbo.KundeKostenstelleView.strKsName1, dbo.KundeKostenstelleView.strKsName2, dbo.KundeKostenstelleView.strKsStrasse, dbo.KundeKostenstelleView.strKsHausNr,
                         dbo.KundeKostenstelleView.strKsPlz, dbo.KundeKostenstelleView.strKsOrt, dbo.EmpfAdr.strStrasse, dbo.EmpfAdr.strHausNr, dbo.EmpfAdr.strPlz, dbo.EmpfAdr.strOrt, dbo.EmpfAdr.strLand, dbo.EmpfAdr.strOrgStrasse,
                         dbo.EmpfAdr.strOrgHausNr, dbo.EmpfAdr.strOrgLand, dbo.EmpfAdr.strOrgPlz, dbo.EmpfAdr.strOrgOrt, dbo.EmpfAdr.fKorrigiert, dbo.SendungDet.lGewicht, dbo.SendungDet.lLeistungID, dbo.SendungDet.dtPlanZustellung,
                         dbo.SendungDet.fRedress, dbo.SendungDet.fZustellungOK, dbo.SBB.dtErfassungszeit AS [Sendung Erfassungszeit], dbo.SBB.lImageCount AS [Anzahl Bilder], dbo.SBB.strUPOC AS SendungsUPOC,
                         dbo.Artikel.strBez AS Artikelbezeichnung, dbo.SendungDet.curPreis
FROM            dbo.SBB INNER JOIN
                         dbo.SendungDet ON dbo.SBB.lSBBID = dbo.SendungDet.lSBBID INNER JOIN
                         dbo.EmpfAdr ON dbo.SBB.lSBBID = dbo.EmpfAdr.lSBBID INNER JOIN
                         dbo.Bezirk ON dbo.SendungDet.lBezirkID = dbo.Bezirk.lBezirkID INNER JOIN
                         dbo.SendungFormat ON dbo.SendungDet.lSendungFormatID = dbo.SendungFormat.lSendungFormatID INNER JOIN
                         dbo.KundeKostenstelleView ON dbo.SBB.lKKSID = dbo.KundeKostenstelleView.lKKSID INNER JOIN
                         dbo.Depot ON dbo.Bezirk.lDepotID = dbo.Depot.lDepotID INNER JOIN
                         dbo.Zustellorganisation ON dbo.Depot.lZustellorganisationID = dbo.Zustellorganisation.lZustellorganisationID INNER JOIN
                         dbo.Artikel ON dbo.SendungDet.lArtikelID = dbo.Artikel.lArtikelID

Da 2 dieser Tabellen (SBB und SendungDet) jedoch ca 44 Millionen Datensätze beinhaltet, dauert eine kleine Abfrage wie zum Beispiel:

Code:
use Sendungsmanager
select count(*), dtPlanZustellung from Sendung_Sicht
where dtPlanZustellung >= DateADD(DAY,-10,GETDATE())
group by dtPlanZustellung

knappe 4 Minuten, was nicht vertretbar ist. Die Weboberfläche sollte möglichst schnell abrufbar sein und die Daten sollten möglichst "schnell" zur Verfügung stehen.

für das obige Beispiel habe ich zum Beispiel nun nicht mehr auf die Sendung_Sicht gegriffen, sondern Frage die Anzahl der letzten Tage über die SBB ab. Was mich statt 4 Minuten, nur noch 1 Minute kostet..

Aber, sobald man die Weboberfläche öffnet mit bisher nur diesem Count braucht sie schon über 1 Minute Ladezeit.

Ich will mir nicht ausdenken wie lange es braucht, wenn ich mal aktiv die Sendung_Sicht aufrufe für ein ganzes Jahr mit allen Spalten.

Ich bin überfordert, weil ich mit dem Thema Datenbanken in der Vergangenheit eher weniger zu tun hatte.

Ich weis, es gibt jetzt womöglich nicht eine Anleitung wie zum Beispiel: "Mach einfach XY dann läufts". Aber eventuell können wir gemeinsam, durch diverse Schritte und Optimierungen versuchen, die Ladezeiten und Abfragedauer immens zu verbessern.

Ich freue mich auf Antworten und hoffe, ihr könnt mir da evtl. helfen.

Bis dahin ganz liebe Grüße
Domenic
 
Werbung:

akretschmer

Datenbank-Guru
Beiträge
9.028
wäre es PostgreSQL, würde ich sagen: EXPLAIN (ANALYSE, BUFFER) ... und hier das Select.

Das würde den Ausführungsplan, Schätzungen und reale Werte, Indexnutzung, Buffernutzung etc. anzeigen und Hinweise liefern, wo die Zeit verbraten wird, was dann wieder bei der Optimierung (Indexe etc.) hilft. M$SQL-Server kenne ich nicht, aber vielleicht hat das auch Möglichkeiten, den Ausführungsplan anzuzeigen.
 

MDDaniel

Aktiver Benutzer
Beiträge
32
Du hast im SQL Management Studio die Möglichkeit dir einen grafischen Ausführungsplan anzeigen zu lassen. [STRG] + M
oder vor deinem Befehl "set statistics xml on" (Fast das gleiche)

Damit siehst du welche Tabellen abgefragt, welche Operationen dafür genutzt werden und wie viele Daten dabei verwendet werden (je dicker der Pfeil desto mehr Daten).
Außerdem kriegst du dabei auch Vorschläge wo gegebenenfalls ein Index hilfreich ist.
Die Vorschläge sind aber mit Vorsicht zu genießen, da sie sich nur auf diese eine Abfrage beziehen. Zu viele Indexe können auch wieder kontraproduktiv sein.

Wenn deine zweite Abfrage 1 Minute dauert kannst du davon ausgehen dass kein passender Index zur Verfügung steht.
Bei deiner 1 Abfrage verknüpfst du nach eigener Aussage Millionen von Daten, was unter Umständen eben dauert. Wobei du dich da natürlich fragen darfst ob du wirklich alle Daten brauchst oder ob du die nicht einschränken (vorfiltern) kannst.
 

dabadepdu

Datenbank-Guru
Beiträge
572
Laut "Tabellen" Namen wird in dem Select Statement ein weiterer View verwendet. So kann man vom Draufschauen wirklich nichts dazu sagen.
Wären keine Views eingebunden, so wäre es ein ziemlich "einfaches" oder unkompliziertes Statement. Dazu gehören ein paar Annahmen:
- Inner Joins über Foreign Keys
- Foreign Keys alle geeignet indiziert

2 stellige Millionemengen sind dabei zunächst auch nicht maßgeblich, ein einziger Join mit einer wenig selektiven Tabelle macht aus Millionen vielleicht Tausend.

Je nach Anforderung kann es in solchen Fällen auch effizient sein, Einschränkungen wie in dem Beispielselect als "allererstes" vorzunehmen und dann mit dem kleinen Ergebnis auf die Millionenmengen zu joinen und das dann erst zu aggregieren.
 

domeetr

Benutzer
Beiträge
5
Du hast im SQL Management Studio die Möglichkeit dir einen grafischen Ausführungsplan anzeigen zu lassen. [STRG] + M
oder vor deinem Befehl "set statistics xml on" (Fast das gleiche)

Damit siehst du welche Tabellen abgefragt, welche Operationen dafür genutzt werden und wie viele Daten dabei verwendet werden (je dicker der Pfeil desto mehr Daten).
Außerdem kriegst du dabei auch Vorschläge wo gegebenenfalls ein Index hilfreich ist.
Die Vorschläge sind aber mit Vorsicht zu genießen, da sie sich nur auf diese eine Abfrage beziehen. Zu viele Indexe können auch wieder kontraproduktiv sein.

Wenn deine zweite Abfrage 1 Minute dauert kannst du davon ausgehen dass kein passender Index zur Verfügung steht.
Bei deiner 1 Abfrage verknüpfst du nach eigener Aussage Millionen von Daten, was unter Umständen eben dauert. Wobei du dich da natürlich fragen darfst ob du wirklich alle Daten brauchst oder ob du die nicht einschränken (vorfiltern) kannst.


Hallo MDDaniel,

vielen Dank für deine Antwort ! :)

Ich habe gestern abend noch genau das rausgefunden, habe ein Index erstellt, was mir das Programm vorgeschlagen hat - und siehe da - eine 46 % Performance-Steigerung. Ich habe bisher noch nie Indexe erstellt, außer die Primary-Keys, die das wohl selbst tun (laut Doku MSSQL)

In wie fern meinst du vorfiltern?

Laut "Tabellen" Namen wird in dem Select Statement ein weiterer View verwendet. So kann man vom Draufschauen wirklich nichts dazu sagen.
Wären keine Views eingebunden, so wäre es ein ziemlich "einfaches" oder unkompliziertes Statement. Dazu gehören ein paar Annahmen:
- Inner Joins über Foreign Keys
- Foreign Keys alle geeignet indiziert

2 stellige Millionemengen sind dabei zunächst auch nicht maßgeblich, ein einziger Join mit einer wenig selektiven Tabelle macht aus Millionen vielleicht Tausend.

Je nach Anforderung kann es in solchen Fällen auch effizient sein, Einschränkungen wie in dem Beispielselect als "allererstes" vorzunehmen und dann mit dem kleinen Ergebnis auf die Millionenmengen zu joinen und das dann erst zu aggregieren.

Hallo dabadepdu,

auch dir vielen Dank für die Antwort! :)

ich frage in einem select * from Sendung_Sicht die obere Sicht ab. Hat den Hintergrund, da ich im PHP möglichst "einfach" und mit kurzer Schreibweise das große Abfragen möchte. Ich habe die Spalten schon aussortiert, alle die jetzt noch drinnen sind, werden irgendwie und irgendwann gebraucht. Vielleicht nicht bei einem Count, aber wenns dann um andere Auswertungen geht. Vielleicht baue ich diesbzgl. mehrere Sichten, um mir immer nur das nötigste, je nach Auswertung, anzeigen zu lassen? Oo

Und in wie fern meinst du Einschränkungen als allererstes vorzunehmen, ehe ich auf die nächste kleine abfrage joine?

Liebe Grüße
Domenic
 
Werbung:

MDDaniel

Aktiver Benutzer
Beiträge
32
In wie fern meinst du vorfiltern?

Du hast gesagt, dass 2 deiner Tabellen Millionen von Datensätzen beinhalten. Bei deiner Abfrage gibt es keine Einschränkung womit du alle Datensätze zurückkriegst die sich aufgrund der Kombinationen ergeben.
Das kann unter Umständen doch einiges an Leistungsverbrauch bedeuten.
Die Frage ist, ob man wirklich alle Daten auf einmal braucht oder gezielter Daten aus der Datenbank abfragen kann.
Soll heißen, vielleicht brauchst du nicht alle Daten abzufragen sondern z.B. nur die eines Kunden oder nur die ab einem bestimmten Datum.
Das würde bedeuten die Daten an der Quelle zu selektieren (mit dem Where - Kriterium) statt erst das Anzeigeergebnis zu filtern.

Abhängig ist, dieses Gedankenspiel natürlich von der An- und Verwendung der Daten.

Gruß Daniel
 
Oben