Chaque lot (requête) qui entre dans SQL Server crée une tâche. Les tâches doivent être exécutées et récupérées par un travailleur. Un travailleur est très similaire à un fil. Une tâche reste avec un travailleur jusqu'à ce qu'elle se termine, ce qui libère le travailleur pour qu'il prenne une autre tâche. Le nombre de travailleurs dans le système est limité, configuré par sp_configure 'max worker threads'
. Au minimum, il y a 256 travailleurs, dont environ 35 sont des systèmes. Un agent a besoin d'un planificateur pour s'exécuter et il existe un seul planificateur pour chaque cœur de processeur. Les travailleurs coopèrent pour partager le planificateur.
Certaines tâches génèrent des sous-tâches, comme des requêtes parallèles. Ces tâches sont également mises en file d'attente pour l'exécution et doivent être complétées par un agent. Les tâches qui génèrent des sous-tâches ne peuvent pas être terminées tant que toutes les tâches générées ne sont pas terminées.
Il existe également des tâches système pilotées par l'utilisateur, telles que la prise de contact. Lorsqu'un client ouvre une nouvelle connexion, l'authentification et l'autorisation de prise de contact et de connexion sont effectuées par une tâche, ce qui nécessite un travailleur.
Lorsque 1000 demandes arrivent sur le serveur, 1000 tâches sont créées et mises en file d'attente pour exécution. Les travailleurs libres ramassent des tâches et commencent à les exécuter.Au fur et à mesure qu'ils terminent une tâche, ils reprennent la tâche suivante, jusqu'à ce que toutes les tâches créées par les 1000 requêtes soient terminées.
Les DMVs qui montrent ce qui se passe sont:
Ces détails sont décrits dans SQL Server Batch or Task Scheduling et Slava's blog.
En outre, une fois la tâche en cours d'exécution, la requête sera compilée. La compilation recherchera d'abord le texte des demandes en mémoire et recherchera un plan compilé existant pour une requête avec un plan identique. Vous pouvez lire ma réponse pour Dynamically created SQL vs Parameters in SQL Server pour un examen plus détaillé de la façon dont cela se passe. Voir aussi Execution Plan Caching and Reuse. Une fois qu'un plan est créé, il est lancé en exécution. Une requête comme SELECT ... FROM table
va créer un plan trivial qui a juste un couple d'opérateurs qui récupèrent fondamentalement chaque ligne et la replacent dans le flux TDS vers le client. Un plan de requête est un arbre d'opérateurs, et la requête est toujours exécutée en demandant à la racine de l'arbre pour la ligne suivante, dans une boucle jusqu'à ce que la racine retourne EOF. Les opérateurs de requête dans l'arbre deviennent de plus en plus spécifiques, jusqu'à ce que l'opérateur du bas soit un accès physique au chemin d'accès choisi (l'index ou le tas choisi par l'optimiseur pour satisfaire la requête). Voir SQL Statement Processing. L'accès à l'index demandera toujours les données du pool de mémoire tampon, jamais à partir du disque. Lorsque le pool de mémoire tampon n'a pas la page demandée en cache, un PAGEIOLATCH est placé sur la page et une demande de lecture de la page est soumise au sous-système IO. Les requêtes suivantes pour la même page attendront que cette E/S se termine et, une fois que la page est dans le pool de mémoire tampon, toutes les autres requêtes qui ont besoin de cette page l'obtiendront du pool de mémoire tampon. les pages inutilisées sont expulsées lorsque le pool de mémoire tampon a besoin de pages libres, mais si le système dispose de suffisamment de RAM, la page ne sera jamais expulsée une fois chargée. Les opérations d'index et de segment de mémoire requièrent des lectures anticipées, en anticipant que les pages en amont de la chaîne en cours seront demandées. Les lectures anticipées sont limitées par les fragments d'index contiguos, et c'est à ce moment que la fragmentation de l'index entre en image, car elle réduit la taille des demandes de lecture anticipée, voir Understanding Pages and Extents.
Une autre dimension de l'exécution de la requête est le verrouillage logique des lignes. Pour la stabilité, une lecture peut placer des verrous de ligne ou des verrous de plage, en fonction du modèle d'isolation, sur les lignes qu'elle lit, pour empêcher les mises à jour concurent pendant que la requête traverse une analyse. Sous le niveau d'isolement SNAPSHOT, la requête ne demandera pas de verrous du tout, mais une marque de version sera utilisée pour servir les données demandées à partir du magasin de versions (voir SQL Server 2005 Row Versioning-Based Transaction Isolation). Sous READ UNCOMMITED isolation (ou lorsque nolock hint est utilisé), la requête ne demande pas de verrous sur les lignes lues, mais les lectures sont incohérentes si des mises à jour concurent (les lignes non validées sont lues, la même ligne peut être lue deux fois ou une ligne existante peut ne pas être lu du tout).
+1 Remus se souvient mieux que moi, vous devez sûrement regarder la certification des maîtres Remus? – Andrew
@Andrew: Je n'ai pas beaucoup d'argent à brûler :) –
Sachez ce sentiment - et j'aurais l'hôtel + vols à payer. – Andrew