Category: "Performance"

Dieser Blog ist umgezogen // This Blog has moved:

Liebe Leser
dieser Blog ist hiermit nur noch „Archiv“ und wird nicht mehr weiter gepflegt.
Seit August 2017 finden sich neue Artikel ausschließlich unter der neuen URL:

Dear Readers
this blog is now merely an „archive“ and no longer being updated.
Since August 2017 new articles are exclusively available under the new URL:

Die aufwändige Mehrsprachigkeit (Deutsch und Englisch professionell manuell übersetzt) wird beibehalten – aber Layout-technisch anders gelöst. Damit dürfte ich immer noch den einzigen mehrsprachigen IT-Blog weltweit betreiben.
Ich hoffe, das neue Design gefällt Ihnen.

The complex multilingualism (German and English professionally manually translated) is being continued – but solved differently in terms of layout. With that I most likely still operate the only multilingual IT-Blog worldwide.
I hope you like the new design.



Mein aktueller Artikel, der erstmalig ausschließlich auf der neuen Website zu finden ist, lautet: Optimieren von Workflows mit In-Memory und nativ kompilierten Objekten - oder wie es nicht funktioniert

My currently last article, which is exclusively available at the new website for the first time, is Optimizing workflows with In-Memory and Natively Compiled Objects - or how it does not work


Cu at my new Blog


Where is that Preemptive Wait coming from? Database Ownership and Performance: a journey through SQL Server internals with XEvents, Windbg and Wireshark


In this article I will bring together several techniques for troubleshooting a performance- and security-related “phenomenon” I recently noticed when doing some tests with Natively Compiled Stored Procedures.

In diesem Artikel zeige ich einige Techniken zum Troubleshooten eines Performance- und sicherheitsrelevanten „Phänomens“, das mir kürzlich aufgefallen ist, als ich ein paar Tests mit Natively Compiled Stored Procedures durchführte.


In SQL Server 2014, Natively Compiled Stored Procedures did not support EXECUTE AS CALLER but EXECUTE AS “SpecificUser” was required. This user could be specified with “Username”, “Self” or simply “Owner” – in which case the owner of the procedure usually reverts to the schema owner, which mostly reverts to the Database Owner altogether.

Hintergrund: In SQL Server 2014 unterstützten Natively Compiled Stored Procedures EXECUTE AS CALLER nicht, sondern es war EXECUTE AS “SpecificUser” erforderlich. Dieser Nutzer konnte mit “Username”, “Self” oder einfach “Owner” spezifiziert werden – in dem Fall kehrt der Besitzer der Prozedurnormalerweise zum „schema owner“ zurück, was meistens ganz auf den Database Owner zurückkehrt. 

The phenomenon I encountered was that I noticed some pretty strange long execution times when running a workload consisting of a very basic stored procedure that does nothing more than insert one row of data into a small, unspectacular table.

The insert itself should run in less than a second for 1000 rows, but I could see up to 5 seconds.
The body of the procedure looks like this:

Das Phänomen, dem ich begegnete, war, dass ich einige ziemlich seltsam lange Ausführungszeiten bemerkte, als ich eine Workload laufen ließ, die aus einer sehr einfachen Stored Procedure bestand, die nichts weiter tat, als eine Datenreihe in eine kleine, unspektakuläre Tabelle einzufügen.
Das Insert selbst sollte weniger als eine Sekunde für 1000 Zeilen laufen, doch ich konnte bis zu 5 Sekunden sehen.
Der Inhalt der Prozedur sieht so aus:



INSERT UserSchema.TableName
(4 columns, int and char)



The analysis:

Since neither the query plan nor “Show Statistics ON” showed anything unusual, I took a step back and started a top-down-analysis with the Waits and Queues Methodology (which, if you are new in this area, has been a proven methodology for performance analysis for over a decade and is explained for SQL Server probably for the first time in detail here: SQL Server 2005 Performance Tuning using the Waits and Queues)
Using the new session-level waits-DMV in SQL Server 2016 (sys.dm_exec_session_wait_stats) I saw the following distribution of waits:

Die Analyse:

Da weder der Abfrageplan noch “Show Statistics ON“ irgendetwas Ungewöhnliches zeigten, ging ich einen Schritt zurück und begann eine Top-Down-Analyse mit der Waits and Queues Methode (die, wenn ihr in diesem Bereich neu seid, eine seit über einem Jahrzehnt bewährte Methode zur Performance-Analyse ist und für SQL Server wahrscheinlich zum ersten Mal im Detail hier erklärt wird: SQL Server 2005 Performance Tuning using the Waits and Queues)
Bei der Anwendung der neuen Session-Level Waits-DMV im SQL Server 2016 (sys.dm_exec_session_wait_stats) sah ich die folgende Waits-Verteilung: 


SELECT dm_exec_session_wait_stats.wait_type
, SUM(dm_exec_session_wait_stats.wait_time_ms) - SUM(dm_exec_session_wait_stats.signal_wait_time_ms) AS resource_wait_time_ms
, SUM(dm_exec_session_wait_stats.signal_wait_time_ms) AS signal_wait_time_ms
, SUM(dm_exec_session_wait_stats.wait_time_ms) AS wait_time_ms
, MAX(dm_exec_session_wait_stats.max_wait_time_ms) AS max_wait_time_ms
, SUM(dm_exec_session_wait_stats.waiting_tasks_count) AS waiting_tasks_count
FROM sys.dm_exec_session_wait_stats AS dm_exec_session_wait_stats
INNER JOIN sys.dm_exec_sessions AS dm_exec_sessions
                ON dm_exec_session_wait_stats.session_id = dm_exec_sessions.session_id
WHERE dm_exec_sessions.program_name ='Sarpedon-WorkoadSimulation-InsertProcs'
GROUP BY dm_exec_session_wait_stats.wait_type
ORDER BY max_wait_time_ms DESC;


From this list, Latch-contention, blocking and some waiting for IO is to be expected with a very concurrent workload (50 threads trying to insert on the last page).
The wait-types marked red are the ones that caught my attention.
As Preemptive waits are a quite different beast, and I initially thought maybe there was some authentication issue with the client, I decided to take a look at the CMEMTHREAD.

Von dieser Liste sind Latch-contention, Blocking und einiges Warten auf IO bei einer sehr simultanen Workload zu erwarten (50 Threads, die versuchen, sich auf der letzten Page einzufügen).
Die rot-markierten Wait-Typen sind diejenigen, auf die ich aufmerksam wurde.
Da Preemptive Waits ein spezielles Biest sind, und ich anfangs dachte, dass es vielleicht ein Authentifikationsproblem beim Client gab, entschied ich mich, einen Blick auf den CMEMTHREAD zu werfen.  

The CMEMTHREAD is an indicator that many threads are contending simultaneously for a thread-safe memory object.
Now since we are running a highly concurrent workload, I could just leave it at that, but remember: “Never make quick decisions by confusing symptom with cause”. Keep looking for the real cause. (A good article by Paul Randal on exactly this issue: “Avoiding Knee-Jerk Performance Troubleshooting”)

So, the question is, which memory object is so special here.

Der CMEMTHREAD ist ein Indikator dafür, dass viele Threads gleichzeitig um ein thread-safe Memory-Object konkurrieren.
Nun, da wir eine höchst konkurrierende Workload laufen haben, könnte ich es einfach darauf beruhen lassen, doch denkt dran: „Niemals schnelle Entscheidungen treffen, indem man das Symptom mit der Ursache verwechselt.“ Sucht weiter nach der wahren Ursache. (Hier ein guter Artikel von Paul Randal zu genau diesem Thema: “Avoiding Knee-Jerk Performance Troubleshooting”)

Also ist die Frage, welches Memory-Object hier so besonders ist.  

Time for Extended Events

One of the niftiest features of extended events is, that you can get a full stack dump of just a single thread, using the Action “sqlserver.create_dump_single_thread”. ”. Similarly, using “package0.callstack” you can get a callstack of the last 16 frames.
 You can analyze the outcome with Windbg. – Or, using Trace Flag 3656, you can even query the Extended Event targets directly with XQuery from within Management Studio and the callstack will be materialized, provided you have loaded the correct symbols. (Nothing you should do on a production Server!)
(An example how to do that can be found here: Resolving DTC Related Waits and Tuning Scalability of DTC)

With the dump opened in Windbg the following function calls inside the SQL Server engine can be seen:

Zeit für Extended Events

Eine der raffiniertesten Features von Extended Events ist, dass man einen vollständigen Stack Dump von einem einzelnen Pfad erhalten kann, wenn man die Action “sqlserver.create_dump_single_thread” verwendet.
Auf ähnliche Weise kann man einen Callstack der letzten 16 Frames erhalten, wenn man “package0.callstack” verwendet.
Man kann das Ergebnis mit Windbg analysieren – oder, wenn man Trace Flag 3656 verwendet, kann man sogar die Extended Event Targets direkt mit XQuery aus Management Studio heraus abfragen und der Callstack wird materialisiert. (Nichts, das man auf einem Produktions-Server machen sollte!)

(Ein Beispiel dafür, wie das gemacht werden kann, ist hier: Resolving DTC Related Waits and Tuning Scalability of DTC)

Mit dem in Windbg  geöffneten Dump können die folgenden Funktions-Calls in der SQL Server Engine gesehen werden:



The Stack dump rings a bell. Right before allocating the memory (CMemThread<CMemObj>::Alloc (red), several functions with very familiar names were called (orange):

Bei dem Stack Dump läuten doch einige Glocken. Kurz vor dem Zuteilen des Memory (CMemThread<CMemObj>::Alloc (rot) wurden mehrere Funktionen mit sehr bekannt klingenden Namen abgerufen (orange):


And those in turn must have been caused by the sqllang!CAutoExecuteAsContext::Set, sqllang!CMsqlExecContext::FExecute and so on (green).
At this point I pretty much knew where to look. But just to show you an example of how this can be done without even touching Windbg, here is an (accumulated and commented) result from the Extended Event callstack-Action:

Und diese wiederum müssen von sqllang!CAutoExecuteAsContext::Set, sqllang!CMsqlExecContext::FExecute verursacht worden sein, und so weiter (grün).
In diesem Moment wusste ich im Prinzip schon, wo ich suchen musste. Aber um euch ein Beispiel zu zeigen, wie man das auch machen kann, ganz ohne Windbg anzurühren, ist hier ein (gesammeltes und kommentiertes) Ergebnis der Extended Event Callstack-Action:  



This callstack results from the PREEMPTIVE_OS_LOOKUPACCOUNTSID Wait-Type, which I noticed would happen exactly once per procedure call. When analyzing different callstacks together I could draw the conclusion that the following function calls lead to the respective Wait-Types:

Dieser Callstack resultiert vom PREEMPTIVE_OS_LOOKUPACCOUNTSID Wait-Type, was, wie ich bemerkte, genau einmal pro Procedure Call geschehen würde. Beim Analysieren verschiedener Callstacks zusammen konnte ich die Schlussfolgerung ziehen, dass die folgenden Funktions-Calls zu den jeweiligen Wait-Types führen:

sqllang.dll!LookupAccountNameInternal -> PREEMPTIVE_OS_LOOKUPACCOUNTSID
sqllang.dll!CWindowsSecurityPrimaryInfo::GetNtGroupsViaAuthZ -> PREEMPTIVE_OS_AUTHZINITIALIZERESOURCEMANAGER
sqllang.dll!CWindowsSecurityPrimaryInfo::Init -> PREEMPTIVE_OS_AUTHORIZATIONOPS

The Preemptive Waits read from the Extended Events file-target can be ordered in their occurrence (from top to bottom), leading to the following picture:

Die Preemptive Waits, aus dem Extended Events Datei-Ziel gelesen, können nach ihrem Auftreten sortiert werden (von oben nach unten), was folgendes Bild ergibt:



The here unreadable callstack for the call to AUTHORIZATIONOPS (undocumented) on the bottom.

Der hier unlesbare Callstack für den Call AUTHORIZATIONOPS (undokumentiert) unten. 


First outcome:

From those calls one can deduct that not the client is authenticating at SQL Server, but actually the procedure call itself causes Windows API calls (LOOKUPACCOUNTSID, AUTHZINITIALIZERESOURCEMANAGER) for authentication purposes.
Now at the very latest it’s time to check the ownership-chain for the stored procedure.
So I checked the header of the proc, and indeed, just as I expected it contained a “WITH EXECUTE AS OWNER”.
That alone can’t be it, so the question is, who is the owner. I already suspected it and there it was: The database was owned by a LOCAL Windows account.
Now, that is rare, but it all makes sense now: For every execution of the procedure, the ownership had to be verified – and since it is a Windows-Account, it had to go out of SQL Server OS, using a Preemptive call to Windows, wait, and continue only after Windows returns control of this thread back to SQL Server.

Erstes Ergebnis:

Aus diesen Call lässt sich ableiten, dass es nicht der Client ist, der sich bei SQL Server authentifiziert, sondern dass es tatsächlich der Procedure Call selbst ist, der Windows API Calls (LOOKUPACCOUNTSID, AUTHZINITIALIZERESOURCEMANAGER) für Authentifizierungszwecke verursacht.
Spätestens jetzt ist es an der Zeit, die Besitzerkette für die Stored Procedure zu überprüfen. Also habe ich den Kopf der Prozedur geprüft, und tatsächlich, genau wie ich erwartet hatte, enthielt es ein “WITH EXECUTE AS OWNER”.
Das allein kann es nicht sein, also stellt sich die Frage, wer der Owner ist. Ich vermutete es bereits, und da war es: Die Datenbank gehörte zu einem LOKALEN Windows-Konto.
Nun, das ist eher selten, doch jetzt ergibt alles Sinn: Für jede Ausführung der Prozedur musste der Besitz verifiziert werden – und da es ein Windows-Konto ist, musste es raus aus SQL Server OS gehen, indem ein Preemptive Call an Windows verwendet wird, dann warten, und erst dann weitermachen, nachdem Windows die Kontrolle dieses Pfades an SQL Server zurückgegeben hatte.


Testing the improvement options:

Now, obviously, I did not stop here but rather made some more tests. Based on the fact that there are 3 possible types of owner for objects within SQL Server, I compared the execution times (and waits) between those 3 possible
Database owner-types:

1.       SQL Account

2.       Windows DomainAccount

3.       Local Windows Account

- I did also test with Admin vs. non-Admin and NTLM vs. Kerberos but saw no difference.

Testen der Verbesserungsmöglichkeiten:

Natürlich hörte ich nicht hier auf, sondern machte noch weitere Tests. Ausgehend von der Tatsache, dass es mögliche Typen von Owner für Objekte innerhalb SQL Server gibt, verglich ich die Ausführungszeiten (und Wartezeiten) zwischen diesen 3 möglichen Datenbank-Owner-Types:

  1. SQL Account
  2. Windows DomainAccount
  3. Local Windows Account

- Ich testete auch mit Admin vs. non-Admin und NTLM vs. Kerberos, stellte jedoch keinen Unterschied fest. 

So here is the result of the Performance-Comparison with different Database-/Procedure-Owners:

Hier ist also das Ergebnis des Performance-Vergleichs mit unterschiedlichen Datenbank-/Procedure-Owners:





1)      The obvious: Using a local Windows Account results in a huge performance-penalty for such a simple INSERT-statement

2)      Using a Domain Account I could notice that every 10 minutes the next execution would be a bit slower.


  1. Das Offensichtliche: Die Verwendung eines lokalen Windows-Kontos führt zu eine riesigen Performance-Impakt für ein solch simples INSERT-Statement

  2. Beim Verwenden eines Domain-Kontos konnte ich sehen, dass die nächste Ausführung alle 10 Minuten etwas langsamer war. 

Further analysis

When checking the Wait-stats again, I could see that usually the Windows-Domain-Account had the following simple waits:

Weitere Analyse

Beim erneuten Überprüfen der Warte-Statistiken konnte ich feststellen, dass der Windows-Domain-Account meistens die folgenden einfachen Waits hatte: 




Pretty ok and nothing to worry about. But the first call after 10 minutes would always result in the same wait-types as I observed for the local Windows Account, except that the wait-times are much much lower. (You can compare the below picture with the one from the beginning of the article.)

Ziemlich in Ordnung und nichts, worüber man sich Sorgen machen müsste. Doch der erste Call nach 10 Minuten ergab immer dieselben Wait-Typen, die ich für das lokale Windows-Konto beobachtete, außer dass die Wartezeiten um Vieles geringer sind. (Ihr könnt das Bild unten mit dem am Anfang des Artikels vergleichen.)




Behind the Scenes: Network Tracing

To explain the difference, I ran a Network Trace using Wireshark
And exactly every 10 minutes I saw some additional KERBEROS-traffic going to the Domain Controller. Below you see the opened data frame with the Request for a Ticket Granting Service Ticket (TGS-REQ).

Hinter den Kulissen: Network Tracing

Um den Unterschied zu erklären, führte ich ein Network Trace mit Wireshark aus.
Und genau alle 10 Minuten sah ich einigen zusätzlichen KERBEROS-Traffic zum Domain Controller fließen. Unten seht ihr den geöffneten Datenrahmen mit dem Request for a Ticket Granting Service Ticket (TGS-REQ).




Background infos:

As the User, on whose behalf the service requests the service ticket, is identified using the user name and user realm/domain (SQL\SQLDBOwner in my case), the padata type PA-FOR-USER is used, as you can see in the screenshot. You can even see the Checksum added for protection.

The S4U2self extension of the PA-DATA structure allows a service to obtain a service ticket to itself on behalf of a user. The user is identified to the KDC using the user's name and realm.


Wenn der Nutzer, für den der Service das Service-Ticket anfordert, unter Verwendung des Nutzernamens und user realm/Domäne (SQL\SQLDBOwner in meinem Fall) identifiziert wird, wird der Padata Type PA-FOR-USER verwendet, wie im Screenshot zu sehen. Man kann sogar die Checksum sehen, die zum Schutz hinzugefügt wurde.

Die S4U2self Extension der PA-DATA-Struktur erlaubt einem Service, ein Service-Ticket im Auftrag eines Nutzers für sich selbst zu beziehen. Der Nutzer wird gegenüber dem KCD identifiziert, unter Verwendung des Nutzernamen und Realm. 

Luckily the DC answers right away with a TGS-REP, containing the PA-DATA-structure with ticket for the service that was named in the TGS-REQ from above:

Zum Glück antwortet der DC sofort mit einem TGS-REP, der die PA-DATA-Struktur mit einem Ticket für den oben im TGS-REQ genannten Service enthält:




There is plenty literature available if you want to learn more about the Kerberos Protocol-Elements. Here is a documentation from Microsoft:

Es gibt eine Menge an Literatur, falls ihr mehr über die Kerberos-Protokollelemente erfahren wollt. Hier ist eine Dokumentation von Microsoft:

The 10-minutes puzzle:

1) After doing some extensive testing, I conclude that the 10-minute interval after which a new Ticket Granting Service Ticket-Request is initiated must be a SQL Server specific enhancement for Domain Accounts to avoid making this round trip for every SID-validation. The 10 minutes are consistent and independent from other workload influencers. The cause behind is not documented.

2) The much faster validation for the AD-Account is very fast thanks to some caching in Windows. (Thank you, Jack Richins from formerly SQL Security Team, for reminding me of this)

3) For the local Windows Account, there is no such performance improvement via caching which results in much slower response times.

Das 10-Minuten-Puzzle:

  1. Nach ausgiebigem Testen schließe ich, dass das 10-Minuten-Intervall, nach dem ein neuer Ticket Granting Service Ticket Request eingeleitet wird, eine SQL-Server-spezifische Erweiterung für Domain-Accounts sein muss, um diese Rundreise nicht für jede SID-Validierung machen zu müssen. Die 10 Minuten sind konsistent und unabhängig von anderen Workload-Beeinflussern. Die Ursache dahinter ist nicht dokumentiert.

  2. Die viel schnellere Validierung für das AD-Konto ist so schnell dank einigem Caching in Windows. (Danke, Jack Richins vom ehemaligen SQL Security Team, der mich daran erinnert hat)

  3. Für das lokale Windows-Konto gibt es keine solche Performance-Verbesserung via Caching, was zu viel längeren Antwortzeiten führt.


Final results and learnings:

1)      Using local users for SQL Server can create noticeable impact for short transactions. Yet another reason to stay away from local accounts.

2)      For the SQL Account, naturally no Windows calls are necessary at all, but the performance-advantage compared to the AD-Account is marginal, even for high-speed scenarios.

3)      Network latency matters even between SQL Server and DC. Not just for the initial Login-phase but even for ongoing validations from within SQL-statements.

4)      I can stick to my recommendation for Database Ownerships (SQL Server Database Ownership: survey results & recommendations) :-)

Endergebnis und Gelerntes:

  1. Die Verwendung von lokalen Nutzern für SQL Server kann deutliche Auswirkungen für kurze Transaktionen verursachen. Noch ein weiterer Grund dafür, sich von lokalen Konten fernzuhalten.

  2. Für den SQL Account sind natürlich keine Windows-Calls notwendig, doch der Performance-Vorteil gegenüber dem AD-Account ist geringfügig, selbst für High-Speed-Scenarien.

  3. Netzwerk-Latenz spielt selbst zwischen SQL Server und DC eine Rolle. Nicht nur für die anfängliche Login-Phase, sondern sogar für fortlaufende Validierungen innerhalb von SQL-Statements.

  4. Ich kann meine Empfehlung für Datenbank-Ownerships aufrechterhalten (SQL Server Database Ownership: survey results & recommendations) :-)

I hope you found this an interesting read.

Ich hoffe, dies war eine interessante Lektüre für euch. 




PS: for the geeks among you:

The Stack Dump in Text format together with some comments:

P.S. Für die Geeks unter euch:

Der Stack Dump im Textformat mitsamt einigen Kommentaren:


Child-SP          RetAddr           Call Site

000000e9`2f0b79d8 00007ffe`f9e51118 ntdll!NtWaitForSingleObject+0xa

-> this function is actually deprecated (Hello, Microsoft?)

000000e9`2f0b79e0 00007ff7`04999fef KERNELBASE!WaitForSingleObjectEx+0x94
000000e9`2f0b7a80 00007ff7`04999d7d sqlservr!CDmpDump::DumpInternal+0x22f
000000e9`2f0b7b20 00007ff7`049a15b8 sqlservr!CDmpDump::DumpFilter+0xcd
000000e9`2f0b7c10 00007ffe`ef0ef2cb sqlservr!memset+0x1819
000000e9`2f0b7c40 00007ffe`fc98398d msvcr120!__C_specific_handler+0x93 [f:\dd\vctools\crt\crtw32\misc\amd64\chandler.c @ 162]
000000e9`2f0b7cb0 00007ffe`fc9493a7 ntdll!RtlpExecuteHandlerForException+0xd
000000e9`2f0b7ce0 00007ffe`fc948fbd ntdll!RtlDispatchException+0x197
000000e9`2f0b83b0 00007ffe`f9e58b9c ntdll!RtlRaiseException+0x18d
000000e9`2f0b8b70 00007ff7`04999c9c KERNELBASE!RaiseException+0x68
000000e9`2f0b8c50 00007ffe`f05602c6 sqlservr!CDmpDump::Dump+0x4c
000000e9`2f0b8c90 00007ffe`f105c411 sqllang!SQLDumperLibraryInvoke+0x1f6
000000e9`2f0b8cd0 00007ffe`f105ce94 sqllang!SQLLangDumperLibraryInvoke+0x161
000000e9`2f0b8d80 00007ffe`f102cd0b sqllang!CImageHelper::DoMiniDump+0x475
000000e9`2f0b8f90 00007ffe`f072e9c4 sqllang!stackTrace+0x9db
000000e9`2f0ba9b0 00007ffe`f072f6ae sqllang!XeSqlPkg::IsSystem+0x174
000000e9`2f0bab90 00007ffe`ef2e779a sqllang!XeSqlPkg::CreateDumpSingleThreadActionInvoke+0x1e

-> you can clearly see how this stack dump was created: XEvents

000000e9`2f0babc0 00007ffe`ef2a1b8e sqldk!XeSosPkg::wait_info_external::Publish+0x1a9

-> Now we will see our wait-type when we ask the DMVs or XEvents

000000e9`2f0bac20 00007ffe`ef2a63a4 sqldk!SOS_Scheduler::UpdateWaitTimeStats+0x596
000000e9`2f0bb530 00007ffe`f0d94fac sqldk!SOS_Task::PopWait+0xba
000000e9`2f0bb590 00007ffe`f0d9481e sqllang!CWindowsSecurityPrimaryInfo::GetNtGroupsViaAuthZ+0x75c


000000e9`2f0bb890 00007ffe`f0d956ed sqllang!CWindowsSecurityPrimaryInfo::Init+0x2ce
000000e9`2f0bba00 00007ffe`f041a88b sqllang!GetWindowsSecurityPrimaryInfo+0xbe
000000e9`2f0bba60 00007ffe`f041cadb sqllang!CreateLoginToken+0x2d7
000000e9`2f0bbc50 00007ffe`f041dca8 sqllang!CreateLoginTokenForImpersonation+0xcb2

-> an Impersonation is happening (EXECUTE AS)

000000e9`2f0bc400 00007ffe`f0358342 sqllang!CAutoExecuteAsContext::Set+0xe2d
000000e9`2f0bc680 00007ffe`f001245e sqllang!CSECExecAsRuntimeServices::_Set+0x424
000000e9`2f0bc900 00007ffe`f0012041 sqllang!CMsqlExecContext::FExecute+0x336
000000e9`2f0bcc30 00007ffe`f0d1d83d sqllang!CSQLSource::Execute+0x983
000000e9`2f0bcdd0 00007ffe`f0d1d241 sqllang!CStmtExecProc::XretLocalExec+0x26e
000000e9`2f0bce50 00007ffe`f0d19f98 sqllang!CStmtExecProc::XretExecExecute+0x481
000000e9`2f0bd600 00007ffe`f00119ca sqllang!CXStmtExecProc::XretExecute+0x38
000000e9`2f0bd640 00007ffe`f0012933 sqllang!CMsqlExecContext::ExecuteStmts<1,1>+0x40d
000000e9`2f0bd780 00007ffe`f0012041 sqllang!CMsqlExecContext::FExecute+0xa9e
000000e9`2f0bdab0 00007ffe`f0cd3f6d sqllang!CSQLSource::Execute+0x983
000000e9`2f0bdc50 00007ffe`f0ce0e6c sqllang!ExecuteSql+0x93d
000000e9`2f0be7d0 00007ffe`f0ce1549 sqllang!CSpecProc::ExecuteSpecial+0x15c
000000e9`2f0be8d0 00007ffe`f001a82b sqllang!CSpecProc::Execute+0x299
000000e9`2f0bea00 00007ffe`f0021542 sqllang!process_request+0xe61
000000e9`2f0befd0 00007ffe`f00210a3 sqllang!process_commands_internal+0x2df
000000e9`2f0bf050 00007ffe`ef2a5bfd sqllang!process_messages+0x253
000000e9`2f0bf260 00007ffe`ef2a58f5 sqldk!SOS_Task::Param::Execute+0x231
000000e9`2f0bf860 00007ffe`ef2a554d sqldk!SOS_Scheduler::RunTask+0xaa
000000e9`2f0bf8d0 00007ffe`ef2cd7c8 sqldk!SOS_Scheduler::ProcessTasks+0x3cd
000000e9`2f0bf9b0 00007ffe`ef2cdb10 sqldk!SchedulerManager::WorkerEntryPoint+0x2a1
000000e9`2f0bfa80 00007ffe`ef2cdcd7 sqldk!SystemThread::RunWorker+0x8f
000000e9`2f0bfab0 00007ffe`ef2cd9f8 sqldk!SystemThreadDispatcher::ProcessWorker+0x2de
000000e9`2f0bfb60 00007ffe`fc6e13d2 sqldk!SchedulerManager::ThreadEntryPoint+0x1d8
000000e9`2f0bfc10 00007ffe`fc9603c4 kernel32!BaseThreadInitThunk+0x22
000000e9`2f0bfc40 00000000`00000000 ntdll!RtlUserThreadStart+0x34


Sessions submitted for major conferences 2016. Topics: Security – Performance – In-Memory

Vorträge für die großen Konferenzen 2016 eingereicht. Themen: Sicherheit - Performance - In-Memory

Nach dem tollen Verlauf der deutschen SQLKonferenz im Februar, wo ich die Ehre hatte, zusammen mit Joachim Hammer, dem Program Manager der Security-Teams für die relationalen SQL Engines bei Microsoft in Redmond die neuen Sicherheitsfeatures des SQL Server 2016 vorzustellen (mehr Infos), habe ich nun endlich Zeit gefunden, die nächsten großen Konferenzen dieses Jahres anzugehen.

After the great success of the German SQLKonferenz in February, where I had the honor of presenting the new security features of SQL Server 2016 together with Joachim Hammer, the Program Manager of the security teams of the relational SQL Engines at Microsoft in Redmond (more info), I finally found time to go about the next big conferences this year.

Für den PASS Summit 2016, der wieder in Seattle/USA stattfindet, und auch für den SQLServerGeeks Annual Summit 2016, der in Bangalore/Indien stattfindet habe ich insgesamt 6 Sessions aus den Themengebieten „Sicherheit“, „Performance Analyse“ und „In-Memory“ ausgearbeitet und eingereicht. Dazu kommen 2 ganztägige PreCons zum Thema „Sicherheit“ und „In-Memory“.
Wen es interessiert, zu sehen, was ich diesmal „in Petto“ habe, kann die Abstracts hier einsehen.

For the PASS Summit 2016 which is again taking place in Seattle/USA as well as for the SQLServerGeeks Annual Summit 2016 which is taking place in Bangalore/India, I worked out and submitted 6 sessions altogether from the subject areas “Security,” “Performance Analysis” and “In-Memory.” Added to that 2 full-day PreCons with the topics “Security” and “In-Memory.”
For whoever is interested to see what I have “up my sleeve” this time, can review the abstracts here.



SQL Server Security black belt – attack, protect and keep secure

Security Hardening is a subject which, sooner or later, every DBA will face. Microsoft SQL Server, according to the NIST vulnerability database the most secure RDBMS for years, contains many features that help keep the data secure on different layers. At the same time, ever-new applications which use databases on your servers, support-personnel, deployment-processes, auditors, and other processes and real people are constantly demanding access to your Server.

At this full-day pre-conference you will see how external and internal attackers can gain access to sensitive data. You will then learn how to secure the different attack surfaces of a typical SQL Server, and protect not only Data at Rest but also Data in Use and Data in Transit and learn best practices to prevent common vulnerabilities.

In the second part you will get to know fundamental security principles such as

  • Least Privilege;
  • Segregation of Duties;
  • Reconstruction of Events;
  • Delegation of Authority;

and you will learn how to use built-in functionalities of SQL Server (some limited to v2016) to build your own security frameworks to secure Deployment and Monitoring, separate Job-permissions; how to implement time-based permissions and which techniques can help reconstruct security-relevant events.

If you are in charge of creating or implementing security concepts or need a full picture of attack surface protection and concepts, this session is exactly right for you.


In-Memory in SQL Server 2016 – from 0 to Operational Analytics Hero

The Columnstore Index technology came with SQL Server 2012 in the form of Nonclustered Columnstore, and SQL Server 2014 brought us updatable Clustered Columnstore Indexes and a completely new In-Memory Engine for memory optimized table & indexes.

SQL Server 2016 is adding the updatable Nonclustered Columnstore Indexes that can both operate on row store as well as on memory-optimized tables, called In-Memory Operational Analytics. With the In-Memory engine being extensively improved in terms of both scalability and T-SQL language support, In-Memory will become a viable option in many projects.

On this training day, attendees will be given a complete picture on the current state of technology and how and where to use either In-Memory OLTP or ColumnStore or both for efficient queries and data store.


General sessions:

Extended Events – The Top Features for efficient Traces

Extended Events, which entered the product in SQL Server 2008, are replacing the old SQL Trace & Profiler - and there are many good reasons for that. In this session you will see a selection of the most fascinating possibilities using this Tracing Framework. If you want to find out how to trace in a flexible and lightweight way, how to do advanced analysis directly inside the GUI, how to audit Database and Table-access without Auditing, how to analyze deadlocks without old-fashioned TraceFlags based on the built-in system_health session, this session is just for you. You will also learn how to use the GUI in an effective way for top-down-analysis and what is possible with some XQuery scripting.


Performance Analyzing SQL Server workloads with DMVs and XEvents

This session you will be lead you through an example performance-analysis using mainly DMVs and Extended Events. You will see how a top-down analysis using built-in tools can be conducted. This will include wait statistics on different scopes to identify performance problems and bottlenecks up to identifying query plan changes – with & without using the Query Store of SQL Server 2016. If you are new to performance analyzing this session will give you a practical insight into how to methodically approach performance troubleshooting.


SQL Server 2016 – the evolution of In-Memory technologies

For SQL Server 2014 a completely new In-Memory Engine for memory optimized table & indexes was integrated into SQL Server with in fact very limited functionality.

For SQL Server 2016 the In-Memory engine is being extensively improved in terms of both scalability as well as T-SQL language support. Moreover the ColumnStore index technology has been improved and can now even be combined with memory-optimized tables.

This session will provide an overview of the new possibilities and demonstrate where a particular technology may help – or where you cannot expect benefits. If you are planning to go on SQL Server 2016 any time soon, this session shows you two of the most important features that SQL Server 2016 brings.



SQL Server Security black belt series: Securing Data

You have installed SQL Server and have heard about several “best practices,” maybe renamed the sa account, but now what?

In this session you will see demos of several methods how an attacker can get access to data in Use & in Transit and see which available built-in technologies provide help in mitigating such attacks. You will be given guidance on how to systematically identify possible threats and ne given best practices at hand.

Among the technologies that can be seen are Network sniffing, a Threat Modeling Tool, TDE and the new Always Encrypted technology of SQL Server 2016. This session is mainly targeting Administrators but many concepts and samples should be valuable knowledge for developers as well.


SQL Server Security black belt series: Securing Operations

You got SQL Server up and running and thought you could easily secure it by completely denying all access to everybody else except you and your co-admin, but you realize that there are many more individuals demanding access for daily or weekly operations. You have heard about “Segregation of Duties” and “Least Privilege” and are looking into how you can properly implement it with SQL Server.

In this session you will learn about techniques and approaches on how to implement secure processes in order to ensure both “Least Privilege” and “Segregation of Duties” and at the same time “Reconstruction of Events.” Among the techniques shown are “time based-permissions” and custom server roles for performance analysis and job-monitoring.


“SQL Attack…ed” – SQL Server under attack via SQL Injection

One of the most frequently attacked targets is the data that resides in a database server. SQL Server is considered “secure by default,” but this is only relevant until the first databases and configurations have been changed. This is why most of the exploited weaknesses are due to misconfiguration or weak coding practices as opposed to security bugs in SQL Server itself, of which we had only a few in the last 10 years.

In this purely demo-based session you will see samples of several real-life attacks, from mere reading up to disrupting service availability via various types of manual and automated SQL Injection, including a broadly unknown elevation of privileges attack for a non-sa account.

If you have a database-server which is accessible by processes beyond your direct control or which even can be reached by some kind of frontend applications, and you are unsure what the possible security implications to watch out for, this session is meant for you.


Ich werde natürlich posten, wenn meine Vorträge für 2016 feststehen. Vielleicht sieht man sich ja auf der einen oder anderen Konferenz. :-)

Of course I will post when my presentations for 2016 are fixed. Maybe you can meet me at one or another conference. :-)



SQL Server in Microsoft Azure: How to gain performance by flexibility and save costs at the same time

 SQL Server in Microsoft Azure: Wie man durch Flexibilität Leistung gewinnt und zugleich Kosten spart

Diesmal widme ich mich erstmalig in einem Artikel den Thema Microsoft Azure.
( Was ist Microsoft Azure?)
Unter Microsoft Azure werden mittlerweile eine Unmenge an Diensten bereitgestellt, und einer davon ist das Hosting von virtuellen Machinen, in denen ein SQL Server Dienst läuft. Hierbei sprechen wir also von IaaS (Infrastructure as a Service).

- Hier wird dieses Service-Modell nähergehend erläutert und unter anderem auch dem PaaS-Ansatz gegenübergestellt:
Which Windows Azure Cloud Architecture? PaaS or IaaS?

Eine schöne gegenüberstellende Grafik findet sich in diesem Blog-Artikel:
Windows Azure IaaS vs. PaaS vs. SaaS

Nachdem man sich einmal entschieden hat, dass das Konzept IaaS für einen Teil der eigenen Umgebung Sinn macht, steht die Frage der Konfiguration der SQL Server Systeme an.
Hier werden in dem Azure Portal fertige Images angeboten, die gerade Einsteigern den Zugang erleichtern sollen.
- Tatsächlich kann man mit nur 7 Klicks einen Windows Server inklusive lizensierten SQL Server einrichten, wenn man eine Vorlage aus der Galerie verwendet.

This is the first time that I am tackling Microsoft Azure in an article. ( What is Microsoft Azure?)

A plethora of services is provided by Microsoft Azure by now, of which the hosting of virtual machines running on an SQL Server service is one. This is what we call IaaS (Infrastructure as a Service).

- Here, this service model will be explained in more detail and, among others, compared to the PaaS approach: Which Windows Azure Cloud Architecture? PaaS or IaaS?

- A nice comparative graph is available in this blog article:
Windows Azure IaaS vs. PaaS vs. SaaS

After determining that the concept IaaS makes sense for part of one’s own environment, the issue of the SQL Server Systems configuration will be next. In the Azure Portal ready-made images are available that will facilitate access especially for starters.
- In fact, with only 7 clicks it is possible to set up a Windows Server including a licensed SQL Server when using a template from the gallery



Für den produktiven Einsatz von SQL Server muss man sich jedoch etwas mehr Mühe geben, denn die Standard-Vorlagen enthalten nur eine Daten-Disk, und auf der liegt das Betriebssystem. – Dort möchte man seinen SQL Server aus mehreren Gründen nicht betreiben.
Neben Datenintegrität ist das die IO-Performance.

Microsoft stellt daher auch sogenannte „optimized“ Images -für entweder OLTP- oder OLAP-Szenarien zur Verfügung (Im Screenshot rot umrahmt), welche direkt mit 15 weiteren Data Disks kommen, was dann insgesamt 16 macht.

However, for the productive application of SQL Server some more efforts are required, as the standard templates merely contain a data disc in which the operating systems is located. – Yet there are several reasons as to why one should not run one’s SQL Server here: data integrity and IO performance.

Therefore, Microsoft also provides so-called “optimized” images – for OLTP or OLAP scenarios – (highlighted by red frame in the screenshot) that immediately come with 15 more data discs making a total of 16.


1) Variante 1, der „traditionelle Ansatz“ ist also: mehrere Data Disks und eine Maschine mit entsprechender Unterstützung/CPU-Power.

Die in diesem Fall 15 Daten Disks (neben der OS Disk) werden in 2 Storage Pools zu je 12 bzw. 3 Disks für SQL-Daten und SQL-Logs vorkonfiguriert.

Die maximalen IOPS hängen auch von den zur Verfügung stehenden CPU-Cores ab. Lineare Performance-Steigerungen sollte man auch nicht erwarten.

1) Option 1, the “traditional approach” hence is: several data discs and a machine with corresponding support/CPU power.

The 15 data discs (additionally to the OS disc) in this case are pre-configured for SQL data and SQL logs in 2 storage pools of 12 and 3 discs each.

The maximum IOPS also depend on the available CPU cores. One should not expect linear performance increases anyway.

Das Problem hierbei: Man verliert dabei fast jegliche Flexibilität.
Und zwar hinsichtlich der Ausbaustufe (Performance) und damit letztlich auch in der Preisgestaltung.
Denn um die insgesamt 16 Data Disks zu verwenden, muss man mindestens eine der 8-Core VM-Größen betreiben (A4, A7, A8, A9, D4, D13, D14, G3, G4 und G5), durchgängig.

Lediglich nach oben kann man Skalieren.
- Wer mehr als 16 zusätzliche Datenträger benötigt, muss eine VM mit 16 bzw. 32 Cores (G-Serie) einsetzen und erhält dann die Möglichkeit bis zu 32 bzw. 64 Data Disks neben der OS Disk einzusetzen.
Nach unten ist man dann auf jeden Fall preislich festgelegt.

The problem here is: You lose almost any flexibility, i.e. in terms of configuration level (performance) and ultimately also in terms of pricing.

Because in order to use the total of 16 data discs it is necessary to consistently operate one of the 8-core VM sizes (A4, A7, A8, A9, D4, D13, D14, G3, G4 and G5). It is only possible to scale upwards.

- If you need more than 16 additional data carriers you will have to apply a VM with 16 or 32 cores (G-series), which will enable you to apply up to 32 or 64 data discs besides the OS disc.
In terms of pricing, this will definitely set the limit downwards.

Damit dürfte das Ziel, Kosten durch Cloud-basierte Systeme zu sparen, jedoch schwieriger zu erreichen sein.
Die große Stärke des Cloud-basierten Ansatzes ist es aber, möglichst genau nur dann, wenn man eine bestimmte Leistung (oder Dienst) benötigt, diese anzufordern & zu erhalten, und wenn man sie nicht benötigt, diese auch nicht nutzlos „aktiviert“ zu belassen. Denn man bezahlt ja, was man „abonniert“, was hier nicht unbedingt auch das ist, was man wirklich nutzt.

Unser ideales System sollte also maximal skalierbar sein, und zwar sowohl nach oben und nach unten.

Wenn man sich einmal die Tabellen mit den derzeitigen (Stand 30.4.2015) virtuellen Maschinen und deren Performance-Kerngrößen vor Augen führt, wird es sicherlich klarer.
Es gibt derzeit 3 Serien auf dem Standard-Tier: A, D und G, wobei die G-Serie die mit der größten Power ist – und damit auch am teuersten.

This, however, makes it more difficult to reach the goal of saving costs through cloud-based systems.

Yet the great strength of the cloud-based approach is ideally only when requiring a specific performance (or service) to request and receive it, and when not needed, to not leave it idly “activated.” For you only pay for what you “subscribe” to, which in this case is not necessarily what you actually use.

Our ideal system, thus, should be maximally scalable, both upwards and downwards.

This will probably become clearer if you look at the charts with the current (status: 30 April 2015) virtual machines and their performance core sizes.

At the moment, the standard tier comprises 3 series: A, D and G, with the G-series being that of the greatest power – and hence the most expensive.



Zu sehen sind die Anzahl der dedizierten CPU-Cores, die Größe des Arbeitsspeichers, die Größe der Temp-Disk, und, ganz wichtig für die Skalierbarkeit: die Anzahl der maximal erlaubten Datenträger neben der OS-Disk selber.

Pro Datendisk erhält man bis zu 500 IOPS. Um mehr IOPS zu erhalten, benötigt man also mehr Data Disks – aber auch mehr CPU Cores.
Wenn man jedoch eine Maschine mit 16 Data Disks verwendet, kann man in Zeiten geringerer Auslastung kaum herunter-skalieren. Eine A2 beispielsweise für eine Art Minimal-Betrieb ist damit unerreichbar. Und wenn man noch mehr Data Disks benötigt um IO-Peaks abfangen zu können, schränkt man sich noch mehr ein und muss dauerhaft die teuersten Maschinen bezahlen.

You can see the number of dedicated CPU cores, the size of the working memory, the size of the temp disc, and, very important for the scalability: the number of the maximally permitted data carriers besides the OS disc itself.

Per data disc you get up to 500 IOPS. To receive more IOPS, thus, you need more data discs – but also more CPU cores. However, when using a machine with 16 data discs it will hardly be possible to scale downwards in times of low utilization rates. An A2, for example, will thus be unreachable for some kind of minimum operation. If you need more data discs to be able to accommodate IO peaks you will restrict yourself further and will have to continually pay for the most expensive machines.

Welche Alternativen gibt es? Wie kann man flexibel sein, um Kosten zu sparen, und gleichzeitig je nach Bedarf auf höhere Maschinen wechseln („Scale-Up“), und auf der anderen Seite nachts oder an Wochenenden seine Maschinen auf minimale CPU’s beschränkt („Scale-Down“).

Are there any alternatives? How to be flexible in order to save costs and at the same time switch to higher machines (“scale-up”) if necessary, and on the other hand restrict your machines to minimal CPUs during nighttime or on weekends (“scale-down”)?

2) Speichern der Data-Files direkt auf Azure Blob-Store

Der offensichtliche Vorteil ist hierbei, dass man keine Data-Disks benötigt – und die sind es, die die Skalierungsmöglichkeiten wesentlich beschränken. Anstelle der Data Disks werden die SQL Server Datenbankdateien direkt im Blob-Store gespeichert.

Die Datenbank-Erstellung kann dann so aussehen:

1) Saving data files directly on the Azure Blob Storage

The obvious advantage here is that data discs are not required – and these are what significantly limit scaling options. Instead of the data discs, the SQL Server database files are stored directly in the Blob storage.

The database creation can look something like this:


Diese Möglichkeit wird seit SQL Server 2014 unterstützt.
Hierbei erhält man ebenfalls pro File 500 IOPS, mit einem Limit von 20.000 je Storage Account, welches generell gilt.

Hier findet sich ein ausführliches Beispiel zur Einrichtung samt Code:
Create a SQL Server 2014 Database directly on Azure Blob storage with SQLXI

Der Nachteil bei dieser Variante ist in meinen Augen die Komplexität. Das Vorgehen mit Einrichtung der Shared Access Signature, die für den Zugriff auf den Blob-Container benötigt wird, ist nicht direkt trivial.

This option is supported since SQL Server 2014.
Here, too, you get 500 IOPS per file, with a general limit of 20.000 per storage account.

Here you can find a detailed example of the setup including a code:
Create a SQL Server 2014 Database directly on Azure Blob storage with SQLXI

The disadvantage of this option is, in my view, the complexity. The approach to creating the Shared Access Signature required for accessing the Blob container is not really trivial.

3) Speichern der Data-Files auf einer Azure Datei-Freigabe

Seit Mai letzten Jahres ist der Azure File-Service (Introducing Microsoft Azure File Service) als Vorschaufeature verfügbar.

Neben „echten“ Verzeichnissen unterstützt dieser Dienst auch Freigaben auf Basis von SMB 2.1.
Hier gibt es ein Maximum an 1000 IOPS pro Share. Das heißt ich benötige für dieselbe Menge an IOPS nur halb so viele Dateien wie für den Direkt-Zugriff auf Azure Blobs.
Wichtig ist, dass man zunächst das Preview-Feature für einen Storage-Account aktiviert hat.

3) Storing data files on an Azure File Share

Since May last year, the Azure file service (Introducing Microsoft Azure File Service) has been available as preview feature.

In addition to “real” directories, this service also supports releases on the basis of SMB 2.1.
Here we get a maximum of 1000 IOPS per share. I.e. for the same amount of IOPS only half as many files are required as for the direct access to Azure Blobs.
It is important to start by activating the preview feature for a storage account.


Danach erzeugt man per PowerShell die notwendigen Shares und verteilt seine Datenbank-Dateien darauf.

Next, you create the necessary shares per PowerShell and distribute your database files on them.

Auch hier gilt natürlich die Begrenzung auf die maximalen 20.000 IOPS je Storage Account. Aber der Zugriff ist in meinen Augen wesentlich einfacher.
Ein Nachteil dieser Variante ist, dass man dafür sorgen muss, dass der SQL Server Dienst erst startet, wenn die Freigaben über Netzwerk auch erreichbar sind.
Abseits von manchmal auftretenden Zugriffsproblemen, die sicherlich dem Preview-Stand geschuldet sind, ist diese Kombination in meinen Augen die am Einfachsten zu Administrierende, nachdem man sich einmal an einen automatisch gesteuerten verzögerten Dienst-Start gewöhnt hat.

Der Azure-File-Dienst wird zurzeit mit 50% Rabatt angeboten, und liegt damit rund 20% unter den Azure-Blob-Storage-Preisen.

A disadvantage of this option is that you have to make sure that the SQL Server service starts only when the shares are available via network.
Aside from occasionally occurring access problems that can probably be attributed to the preview status this combination, as I see it, is the easiest one to administrate – once you got used to the automatically controlled delayed service start. 

The Azure File service is currently offered with a 50% discount and is thus at around 20% below the Azure Blob storage prices.

Der Vorteil der beiden letzten Varianten liegt klar auf der Hand: man ist nicht an eine bestimmte Ausbaustufe des Systems gebunden, sondern kann zu bestimmten Zeiten seinen SQL Server auf einer Maschine mit weit mehr oder auch weit weniger CPU-Cores starten.

The advantage of the latter two options is evident: you are not bound to a particular configuration level of the system but you can start your SQL Server on a machine with far more or also far less CPU cores at certain times.

Ein Wort noch zum Transaktionsprotokoll:

Pro Datenbank gibt es nur eine Log-Datei (mehrere Log-Dateien würden sequentiell beschrieben werden und keinerlei Performance-Vorteile bringen). Dort bringen File-Shares direkt den Vorteil, anstelle von 500 IOPS 1000 IOPS zu liefern. Wenn das nicht ausreicht, bleibt leider nur der traditionelle Ansatz im Zusammenspiel mit Windows Server Storage Spaces: ein Striping aus mehreren Data-Disks für das Transaktionsprotokoll mit dem entsprechenden Skalierbarkeitsnachteil.

One final remark on the transaction log:

There is only one log file per database (several log files would be written to sequentially and not bring any performance advantages). There, the immediate benefit is that file shares deliver 1000 IOPS instead of 500 IOPS. If this is not sufficient, only the traditional approach combined with Windows Server Storage Spaces remains, unfortunately: striping of several data discs for the transaction log with the according scalability disadvantage.

Ich hoffe, ich konnte in diesem Artikel den für mich wichtigsten Vorteil des Cloud-basierten Ansatzes am Beispiel SQL Server etwas näherbringen. Sobald man sich einmal an das „Service-Konzept“ der Cloud gewöhnt hat, und traditionelle Denkmuster in der Form von „Ich benötige eine x-Core-Maschine“ hinter sich lassen kann, kann man durch das Kombinieren von verschiedenen Diensten, wie hier Virtuellen Maschinen und Dateidiensten, sehr kosten- und performance-effiziente Systeme bauen.

Und natürlich sind nicht immer IOPS das Maß der Dinge. Ich habe diese nur zur Vereinfachung über MB/sec gewählt und auch ohne auf die Request-Größe Rücksicht zu nehmen. Im Allgemeinen sind die Werte auf Basis von 4-K sequentiellen Lese-Requests zu verstehen. Das gilt aber für alle Speichermechanismen, die hier angesprochen wurden, und sollte daher zum Zwecke der Vergleichbarkeit ausreichen.

I hope this article made somewhat tangible what to me is the biggest advantage of the Cloud-based approach through the example of SQL Server.  As soon as you get used to the Cloud’s “service concept” and leave behind traditional thinking patterns like “I need an x-core machine” you can build very cost- and performance-efficient systems by combining different services, such as, as demonstrated above, virtual machines and file services.

Of course, IOPS are not always the ultimate performance indicator. I have chosen them over MB/sec for simplifying reasons alone and without taking into account the request-size. In general, the values are to be understood based on 4-K sequential reading requests. This applies to all storage mechanisms that have been addressed here and should therefore suffice for the purpose of comparability.

Wer Interesse hat, sich mit dem Thema noch mehr auseinanderzusetzen ist herzlich willkommen auf dem SQLSaturday Rheinland, einer 1-tägigen kostenfreien Konferenz für SQL Server am 13. Juni in Sankt Augustin.
Und am 12. Juni, also den Tag davor gibt es eine ebenso kostenfreie PreCon, „Hybrid IT Camp: Azure Szenarien & die eigene flexible Infrastruktur für jedermann“. (Short Link:, die ich zusammen mit Patrick Heyde von Microsoft (Blog/Twitter) durchführe.

Those who are interested in further dealing with this topic are welcome to join the free one-day SQL Server conference SQLSaturday Rheinland on 13 June in Sankt Augustin.

On 12 June, the day before, there will also be a free PreCon, Hybrid IT Camp: Azure Szenarien & die eigene flexible Infrastruktur für jedermann (“Azure scenarios & individual, flexible infrastructures for everybody”) (Short Link:, which I will be running with Patrick Heyde (Blog/Twitter) from Microsoft.

Hier noch eine Liste an weiterführenden Links:

Below is a list for further reading:

 Have fun on Azure cloud


PS: Noch ein explizites Dankeschön an Patrick Heyde für seine wertvollen Tipps und Mentoring in Microsoft Azure – auch ich musste mich ja erst einmal an eine neue Denkweise gewöhnen :-)

P.S.: A big “thank you” goes to Patrick Heyde for his valuable tips and mentoring in Microsoft Azure – I, too, had to get used to a new way of thinking :-)

PreCon Performance Analysis & Tuning Techniques at SQLSaturday in Istanbul

PreCon Performance Analyse & Tuning Techniken auf dem SQLSaturday in Istanbul


Was für ein Jahr: nachdem ich bereits  3 SQLSaturdays (Dänemark, Niederlande, Deutschland) hinter mir habe, werde ich nun auch auf dem SQSaturday #258 (5. Okt.) in Istanbul sprechen.
Und nach meiner ersten PreCon dieses Jahr auf dem SQLSaturday in Deutschland, die ich zusammen mit Mladen Prajdić, zum Part “XEvents” gegeben habe, werde ich dieses mal einen ganzen Tag PreCon (4. Okt.) zum Thema “Performance Analyse & Tuning Techniken” geben!


What a year: after already 3 SQLSaturdays (Denmark, Netherlands, Germany) behind me, I will now also speak at SQSaturday #258 (Oct. 5th) in Istanbul, Turkey.
And after my first PreCon this year at the SQLSaturday in Germany, which I was co-presenting together with Mladen Prajdić, on the part “XEvents”, I will now be giving a full day PreCon (Oct. 4th) on “Performance Analysis & Tuning Techniques”!


Ich freue mich wirklich sehr über das Thema und zugleich auch über den Austragungsort.
Istanbul ist für Geschichts- & Fotografie Enthusiasten wie mich ein absolutes Muss. (Meine Facebook Wand erwartet wieder tolle Bilder :)

Zurück zum Technischen: Hier ist die Vortrags-Beschreibung & Agenda:

Sei bereit für einen vollen Tag Abtauchen in SQL Server Performance Analyse.
Diese Session konzentriert sich auf Werkzeuge und Techniken und wie man häufige Probleme löst.
Wir starten auf Betriebssystem-Ebene mit PerfMon, und steigen dann weiter ein in SQL Server Wait Stats Analyse für Flaschenhalsanalyse. Wir verwenden verschiedene Werkzeuge wie SQL Trace & Profiler und den Nachfolger: Extended Events für detaillierte Analyse und sehen auch, welche anderen Tools von Codeplex zur Verfügung stehen.
Wir untersuchen den Plan Cache und Indexierung mithilfe von DMVs und steigen schließlich auch in Sperren und Parallelitätsprobleme ein.