Wie stark wirken sich SQL-Kompilierungen auf die Leistung von SQL Server aus?

20

Ich erstelle ein Profil für eine Instanz von SQL Server 2005 und sehe anhand der PerfMon- SQLServer:SQL Statistics - SQL Compilations/secMetrik, dass der Durchschnitt bei etwa 170 liegt.

Ich habe SQL Profiler ausgepeitscht und nach SP: Compile- oder SQL: Compile-Ereignissen gesucht. Anscheinend existieren sie nicht. Ich habe Stored Procedure/SP:Recompileund TSQL/SQL:StmtRecompileEreignisse gefunden. Die Menge an Daten, die ich im Profiler sehe, deutet darauf hin, dass dies die falschen Ereignisse sind, obwohl ich nicht sicher bin.

Also meine Fragen. Die Antworten auf diese Fragen wären großartig.

  1. Wie kann ich sehen, was genau in SQL Server kompiliert wird?
  2. Habe ich die falschen Metriken ausgewählt, um sie anzusehen? In Perfmon oder SQL Profiler?
  3. In Bezug auf Stored Procedure/SP:Recompileund TSQL/SQL:StmtRecompileEreignisse in SQL Profiler ... ist die Duration-Metrik nicht enthalten. Wie kann ich die Auswirkung dieser Ereignisse auf das System abschätzen, wenn sie keine Möglichkeit bieten, die zeitlichen Auswirkungen auf das System zu erkennen?
AngryHacker
quelle

Antworten:

33

SQL Compilations / Sek. Ist eine gute Metrik, jedoch nur in Verbindung mit Batch Requests / Sek . Zusammenstellungen pro Sekunde sagen an sich nicht viel aus.

Sie sehen 170. Wenn der Batch-Bedarf pro Sekunde nur 200 beträgt (ein wenig übertrieben), müssen Sie der Ursache auf den Grund gehen (höchstwahrscheinlich ein übermäßiger Einsatz von Ad-hoc-Abfragen und Einwegplänen). Wenn Ihre Stapelanforderung pro Sekunde jedoch ungefähr 5000 beträgt, sind 170 Zusammenstellungen pro Sekunde überhaupt nicht schlecht. Es ist eine allgemeine Faustregel, dass die Compilations / Sek. 10% oder weniger als die gesamten Batch Requests / Sek . Betragen sollten .

Wenn Sie wirklich einen Drilldown durchführen möchten, was gerade zwischengespeichert wird, führen Sie die folgende Abfrage aus, bei der die entsprechenden DMVs verwendet werden:

select
    db_name(st.dbid) as database_name,
    cp.bucketid,
    cp.usecounts,
    cp.size_in_bytes,
    cp.objtype,
    st.text
from sys.dm_exec_cached_plans cp
cross apply sys.dm_exec_sql_text(cp.plan_handle) st

So erhalten Sie alle Einwegpläne (Zählung):

;with PlanCacheCte as 
(
    select
        db_name(st.dbid) as database_name,
        cp.bucketid,
        cp.usecounts,
        cp.size_in_bytes,
        cp.objtype,
        st.text
    from sys.dm_exec_cached_plans cp
    cross apply sys.dm_exec_sql_text(cp.plan_handle) st
)
select count(*)
from PlanCacheCte
where usecounts = 1

So ermitteln Sie das Verhältnis der Anzahl der von Ihnen verwendeten Single-Use-Pläne zu allen zwischengespeicherten Plänen:

declare @single_use_counts int, @multi_use_counts int

;with PlanCacheCte as 
(
    select
        db_name(st.dbid) as database_name,
        cp.bucketid,
        cp.usecounts,
        cp.size_in_bytes,
        cp.objtype,
        st.text
    from sys.dm_exec_cached_plans cp
    cross apply sys.dm_exec_sql_text(cp.plan_handle) st
    where cp.cacheobjtype = 'Compiled Plan'
)
select @single_use_counts = count(*)
from PlanCacheCte
where usecounts = 1

;with PlanCacheCte as 
(
    select
        db_name(st.dbid) as database_name,
        cp.bucketid,
        cp.usecounts,
        cp.size_in_bytes,
        cp.objtype,
        st.text
    from sys.dm_exec_cached_plans cp
    cross apply sys.dm_exec_sql_text(cp.plan_handle) st
    where cp.cacheobjtype = 'Compiled Plan'
)
select @multi_use_counts = count(*)
from PlanCacheCte
where usecounts > 1

select
    @single_use_counts as single_use_counts,
    @multi_use_counts as multi_use_counts,
    @single_use_counts * 1.0 / (@single_use_counts + @multi_use_counts) * 100
        as percent_single_use_counts

Die Dauer, die über eine SQL Server-Ablaufverfolgung erfasst wird, steht für die Neukompilierungsereignisse nicht zur Verfügung. Es ist nicht so wichtig, die Dauer oder den Schmerz zu sehen, den die Kompilierung des Plans verursacht, da Sie im Einzelfall nicht viel tun können. Die Lösung besteht darin, zu versuchen, Kompilierungen und Neukompilierungen durch die Wiederverwendung von Plänen (parametrisierte Abfragen, gespeicherte Prozeduren usw.) einzuschränken.

Thomas Stringer
quelle
9

Es gibt drei relevante Zähler, die mit PerfMon (oder einer anderen Lösung von Drittanbietern) aufgezeichnet werden sollten. Der entscheidende Punkt ist zu diese Statistiken irgendwie aufzuzeichnen .

  • SQL Statistics \ Batch Requests / Sek
  • SQL-Statistik \ SQL-Kompilierungen / Sek
  • SQL-Statistik \ SQL-Neukompilierungen / Sek

Wie Thomas Stringer erwähnte , ist es gut, das Verhältnis von Zusammenstellungen / Chargenanforderung im Auge zu behalten. Natürlich ist niedriger besser, aber es gibt nur Richtlinien für das, was "gut" ist, und nur Sie können entscheiden, was akzeptabel ist. Der absolute Leistungszuwachs, den Sie durch Verringern der Anzahl der Kompilierungen erzielen, hängt von vielen Faktoren ab.

Ich schaue mir auch gerne das Verhältnis von Neuzusammenstellungen / Zusammenstellungen an , um ein Gefühl für den Umfang der Wiederverwendung von Abfrageplänen zu bekommen. Wieder ist niedriger besser. In diesem Fall möchten Sie jedoch, dass Neukompilierungen im System stattfinden, wenn sich die Statistik ändert (wenn die Datenbank schreibgeschützt ist und Sie Neukompilierungen haben ... möglicherweise liegt ein Fehler vor). Wie ich bereits sagte, gibt es nur Richtlinien für das, was "gut" ist.

Was Sie wirklich tun möchten, ist, diese Zahlen im Laufe der Zeit zu bestimmen. Wenn Sie also einen großen Anstieg in einem der beiden Verhältnisse feststellen, wurde etwas bereitgestellt, das Abfragepläne nicht korrekt verwendet (im Idealfall wird dies während des Testens abgefangen) - verwenden Sie Shark's Analyse-Anfragen, um die Schuldigen zu finden. Außerdem finden Sie hier häufig neu kompilierte Abfragen:

SELECT TOP 50
    qs.plan_generation_num,
    qs.execution_count,
    qs.statement_start_offset,
    qs.statement_end_offset,
    st.text
    FROM sys.dm_exec_query_stats qs
    CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
    WHERE qs.plan_generation_num > 1
    ORDER BY qs.plan_generation_num DESC

Wenn Sie auch Statistiken zur CPU-Auslastung aufzeichnen, können alle Statistiken miteinander korreliert werden, um herauszufinden, wie weh es tut und wie viel Ihre Korrekturen helfen. In der Praxis habe ich festgestellt, dass selbst eine einzige Strategie für einen fehlerhaften Abfrageplan in einem Kern-Sproc einen Server in die Knie zwingen kann. offensichtlich YMMV.

Jon Seigel
quelle