Unendliche Suche im Query Store

10

Ich werde von Anfang an sagen , dass meine Frage / Problem ähnlich sieht diesen vorherigen, aber da ich bin nicht sicher , ob die Ursache oder die Start-Informationen die gleiche ist, habe ich beschlossen , meine Frage mit einem paar mehr Details zu veröffentlichen.

Problem zur Hand:

  • Zu einer seltsamen Stunde (gegen Ende des Geschäftstages) beginnt sich eine Produktionsinstanz unregelmäßig zu verhalten:
    • hohe CPU für die Instanz (von einer Grundlinie von ~ 30% ging es auf etwa das Doppelte und wuchs immer noch)
    • erhöhte Anzahl von Transaktionen / Sek. (obwohl sich beim Laden der App nichts geändert hat)
    • erhöhte Anzahl von Leerlaufsitzungen
    • seltsame Blockierungsereignisse zwischen Sitzungen, die dieses Verhalten nie zeigten (selbst das Lesen nicht festgeschriebener Sitzungen verursachte Blockierungen)
    • Die obersten Wartezeiten für das Intervall waren keine Seitenverriegelung auf dem 1. Platz, wobei Sperren den 2. Platz einnahmen

Erste Untersuchung:

  • Mit sp_whoIsActive haben wir gesehen, dass eine von unserem Überwachungstool ausgeführte Abfrage extrem langsam ausgeführt wird und viel CPU beansprucht, was vorher nicht geschehen ist.
  • seine Isolationsstufe wurde unverbindlich gelesen;
  • Wir haben uns den Plan angesehen, bei dem wir verrückte Zahlen gesehen haben: StatementEstRows = "3.86846e + 010" mit etwa 150 TB geschätzten Daten, die zurückgegeben werden sollen
  • Wir hatten den Verdacht, dass eine Abfrageüberwachungsfunktion des Überwachungstools die Ursache war, und haben diese Funktion deaktiviert (wir haben auch ein Ticket bei unserem Anbieter geöffnet, um zu überprüfen, ob ihm ein Problem bekannt ist).
  • Von diesem ersten Ereignis an passierte es noch einige Male. Jedes Mal, wenn wir die Sitzung beenden, wird alles wieder normal.
  • Wir stellen fest, dass die Abfrage einer der von MS in BOL für die Überwachung von Abfragespeichern verwendeten Abfragen sehr ähnlich ist - Abfragen, deren Leistung kürzlich zurückgegangen ist (Vergleich verschiedener Zeitpunkte)
  • Wir führen dieselbe Abfrage manuell aus und sehen dasselbe Verhalten (die verwendete CPU nimmt ständig zu, die Wartezeiten zwischen den Latches steigen, unerwartete Sperren usw.).

Schuldige Abfrage:

Select qt.query_sql_text, 
    q.query_id, 
    qt.query_text_id, 
    rs1.runtime_stats_id AS runtime_stats_id_1,
    interval_1 = DateAdd(minute, -(DateDiff(minute, getdate(), getutcdate())), rsi1.start_time), 
    p1.plan_id AS plan_1, 
    rs1.avg_duration AS avg_duration_1, 
    rs2.avg_duration AS avg_duration_2,
    p2.plan_id AS plan_2, 
    interval_2 = DateAdd(minute, -(DateDiff(minute, getdate(), getutcdate())), rsi2.start_time), 
    rs2.runtime_stats_id AS runtime_stats_id_2
From sys.query_store_query_text AS qt 
Inner Join sys.query_store_query AS q 
    ON qt.query_text_id = q.query_text_id 
Inner Join sys.query_store_plan AS p1 
    ON q.query_id = p1.query_id 
Inner Join sys.query_store_runtime_stats AS rs1 
    ON p1.plan_id = rs1.plan_id 
Inner Join sys.query_store_runtime_stats_interval AS rsi1 
    ON rsi1.runtime_stats_interval_id = rs1.runtime_stats_interval_id 
 Inner Join sys.query_store_plan AS p2 
    ON q.query_id = p2.query_id 
Inner Join sys.query_store_runtime_stats AS rs2 
    ON p2.plan_id = rs2.plan_id 
Inner Join sys.query_store_runtime_stats_interval AS rsi2 
    ON rsi2.runtime_stats_interval_id = rs2.runtime_stats_interval_id
Where rsi1.start_time > DATEADD(hour, -48, GETUTCDATE()) 
    AND rsi2.start_time > rsi1.start_time 
    AND p1.plan_id <> p2.plan_id
    AND rs2.avg_duration > rs1.avg_duration * 2
Order By q.query_id, rsi1.start_time, rsi2.start_time

Einstellungen und Infos:

  • SQL Server 2016 SP1 CU4 Enterprise auf einem Windows Server 2012R2-Cluster
  • Abfragespeicher aktiviert und standardmäßig konfiguriert (keine Einstellung geändert)
  • Datenbank aus einer SQL 2005-Instanz importiert (und immer noch auf Kompatibilitätsstufe 100)

Empirische Beobachtung:

  • Aufgrund extrem verrückter Statistiken haben wir alle * plan_persist ** -Objekte verwendet, die im fehlerhaften geschätzten Plan verwendet wurden (noch kein tatsächlicher Plan, da die Abfrage nie abgeschlossen wurde) und Statistiken überprüft. Einige der im Plan verwendeten Indizes hatten keine Statistiken (DBCC SHOWSTATISTICS hat nichts zurückgegeben. Wählen Sie aus sys.stats die Funktion NULL stats_date () für einige Indizes aus

Schnelle und schmutzige Lösung:

  • Erstellen Sie manuell fehlende Statistiken zu Systemobjekten, die sich auf Query Store oder beziehen
  • Erzwingen Sie, dass die Abfrage mit dem neuen CE (Traceflag) ausgeführt wird. Dadurch werden auch die erforderlichen Statistiken erstellt oder aktualisiert
  • Ändern Sie die Kompatibilitätsstufe der Datenbank auf 130 (daher wird standardmäßig das neue CE verwendet).

Meine eigentliche Frage wäre also:

Warum würde eine Abfrage im Abfragespeicher Leistungsprobleme für die gesamte Instanz verursachen? Befinden wir uns mit Query Store in einem Fehlergebiet?

PS: Ich werde in Kürze einige Dateien (Druckbildschirme, E / A-Statistiken und Pläne) hochladen.

Auf Dropbox hinzugefügte Dateien .

Plan 1 - anfänglicher verrückter geschätzter Plan in der Produktion

Plan 2 - tatsächlicher Plan, altes CE, in einer Testumgebung (gleiches Verhalten, gleiche verrückte Statistiken)

Plan 3 - aktueller Plan, neues CE, in einer Testumgebung

Marian
quelle
1
Am Ende haben wir den Abfragespeicher deaktiviert. Wir sind uns nicht sicher, was die Hauptursache war (wir hatten mit Sicherheit mehr als ein Problem). Meiner Meinung nach würde die CPU alles hochfahren, was wir angeklickt haben, um Statistiken aus dem Abfragespeicher anzuzeigen.
A_V

Antworten:

6

Wie ich in der Antwort sagte, zeigte der empirische Test, dass es Indizes für sys.plan_persisted * -Systemobjekte gab, ohne dass (keine) Statistiken darüber erstellt wurden. Ich vermute, das liegt daran, dass die Datenbank von einer SQL 2005-Instanz migriert und eine Weile auf Kompatibilitätsstufe 100 gehalten wurde, sodass das neue CE nicht verwendet werden konnte.

Überprüfung der Zeilenanzahl:

Select count(1) from NoNameDB.sys.plan_persist_runtime_stats with (nolock) --60362   
Select count(1) from NoNameDB.sys.plan_persist_plan with (nolock) --1853    
Select count(1) from NoNameDB.sys.plan_persist_runtime_stats_interval with (nolock) --671    
Select count(1) from NoNameDB.sys.plan_persist_query with (nolock) --1091    
Select count(1) from NoNameDB.sys.plan_persist_query_text with (nolock) --911

Dies zeigte, dass die anfänglichen Schätzungen falsch waren. Fertig mit einer DAC-Verbindung, andernfalls können die Tabellen nicht abgefragt werden.

Statistikprüfung:

DBCC SHOW_STATISTICS ('sys.plan_persist_runtime_stats_interval', plan_persist_runtime_stats_interval_cidx);    
DBCC SHOW_STATISTICS ('sys.plan_persist_runtime_stats', plan_persist_runtime_stats_idx1);    
DBCC SHOW_STATISTICS ('sys.plan_persist_runtime_stats', plan_persist_runtime_stats_cidx);    
DBCC SHOW_STATISTICS ('sys.plan_persist_plan', plan_persist_plan_cidx);    
DBCC SHOW_STATISTICS ('sys.plan_persist_plan', plan_persist_plan_idx1);    
DBCC SHOW_STATISTICS ('sys.plan_persist_query', plan_persist_query_cidx)    
DBCC SHOW_STATISTICS ('sys.plan_persist_query_text', plan_persist_query_text_cidx);

Dies zeigte, dass einige Indizes leere Statistiken hatten (fehlend, keine, null).

Erste Korrektur:

UPDATE STATISTICS sys.plan_persist_runtime_stats WITH fullscan;
UPDATE STATISTICS sys.plan_persist_plan WITH fullscan;
UPDATE STATISTICS sys.plan_persist_runtime_stats_interval WITH fullscan;
UPDATE STATISTICS sys.plan_persist_query WITH fullscan;
UPDATE STATISTICS sys.plan_persist_query_text WITH fullscan;

Diese Art von korrigierte die Statistiken und beendete die Abfrage in 10-12 Sekunden.

Zweiter Fix :

(nur in einer Testumgebung überprüft) und höchstwahrscheinlich bestand die richtige, da sie die besten Statistiken für die Abfrage zeigte, darin, die Kompatibilitätsstufe der Datenbank auf 130 zu ändern. Das Endergebnis war, dass die Abfrage in etwa 10-12 Sekunden mit endete normale Anzahl Statistiken (10k Zeilen).

Zwischenfix :

DBCC TRACEON (2312) -- new CE

Einige verwandte Hilfen zu Statistiken für versteckte Systemtabellen.

Marian
quelle
3

Das zugrunde liegende Problem, das sichtbar wird, wenn Sie den eigentlichen Plan in SSMS öffnen und die CPU-Auslastung untersuchen (oder XML untersuchen), ist Knoten 32, eine TVF. Der Schuldige an langsamen Query Store-Abfragen ist der wiederholte Zugriff auf die speicherinternen TVFs .

TVF Kosten

Es spielt keine Rolle, wie viele Zeilen von diesen TVFs zurückgegeben werden, sondern nur, wie oft auf sie zugegriffen wird. Die Lösung ist alles, was Sie tun können, um Ihre Pläne davon abzuhalten, sie mehrmals zu lesen.

Basierend auf meinem begrenzten Debugging (sowohl in Bezug auf Fähigkeiten als auch in Bezug auf die aufgewendete Zeit) gehe ich davon aus, dass der gesamte Speicher, der für die bestimmte speicherinterne Komponente von Query Store-Daten zugewiesen ist, bei jeder TVF-Ausführung gescannt wird. Ich konnte diese Speicherzuordnung weder mit sp_query_store_flush_dbnoch mit beeinflussen DBCC FREESYSTEMCACHE.

Zu den bisher erfolgreichen Problemumgehungen gehören Planhandbücher, Hinweise ( OPTION(HASH JOIN, LOOP JOIN)hat für mich bisher gut genug funktioniert) und das Ausführen der Abfragespeicherabfragen auf einem schreibgeschützten Knoten einer AG.

Wald
quelle