2010-01-11 8 views
4

Lorsque le serveur SQL reçoit deux requêtes (SELECT * à partir de la table_Same), exactement au même moment et si vous avez un serveur avec plusieurs processeurs, le serveur sq sql peut-il récupérer les données en même temps?Accès concurrent au serveur SQL

J'essaie de comprendre ce qui se passera si une instruction de sélection bon marché qui se termine dans .01 sec, et 1000 utilisateurs exécutent exactement la même requête en même temps. Je pense que ce qui se passera que si le serveur a quatre processeurs, alors le serveur de SQL servira les quatre premiers dans .01 sec et servira les quatre utilisateurs suivants dans 0.02 sec, supplémentaire.

Est-ce encore proche de ce qui se passera réellement?

Je pense que je vais essayer d'utiliser un certain type de code et de loggers pour le tester, ou peut-être qu'il existe des outils de test fiables pour le faire.

Merci

Répondre

14

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).

+0

+1 Remus se souvient mieux que moi, vous devez sûrement regarder la certification des maîtres Remus? – Andrew

+0

@Andrew: Je n'ai pas beaucoup d'argent à brûler :) –

+0

Sachez ce sentiment - et j'aurais l'hôtel + vols à payer. – Andrew

2

Non, votre hypothèse d'un traitement séquentiel n'est pas correct, ce sujet devient très complexe et profond - essayer de faire ce que je sais simple:

Chaque requête a un filet affecté et la L'ordonnanceur utilise un ordonnancement coopératif, et non préemptif, de sorte que chaque thread peut abandonner l'allocation (quanta) de temps avant d'être forcé par le planificateur. Chaque requête va devoir faire des demandes de données à partir du pool de mémoire tampon, ce qui peut signifier attendre sur IO/réseau etc, de sorte qu'ils atteindront des états d'attente et produiront leurs quanta de temps de traitement. Quand un processus n'attend plus sur la ressource, il peut alors entrer à nouveau la liste des threads disponibles à traiter et obtenir un autre délai pour traiter la requête.

En effet, vos requêtes sont exécutées en parallèle, mais vous ne pouvez pas prédire de façon déterministe l'ordre dans lequel les requêtes se termineront. Pour approfondir ce sujet, je pense que le livre de SQL 2008 Internals de Kalen Delaney (Adam Mechanic, Kimberley Tripp, Paul Randal) est un bon point de départ, ou l'ancien livre d'architecture SQL Server 2000 de Ken. Henderson, qui était aussi très bas niveau.

Je devrais me référer aux notes de cours pour me rappeler le processus exact - il faut aller jusqu'à demander - «puisque vous ne pouvez pas affecter cela directement, pourquoi demandez-vous?

+0

Pour vérifier la raison qui me fera Cache une donnée bon marché. Sur la base de ce thread, je ne mettrai pas en cache les données bon marché relatives à un client. Je mettrai en cache toutes les données dont tous les clients ont probablement besoin car le débit d'avg_case diminuera si le nombre d'utilisateurs augmente. Es tu d'accord? Merci – Costa

+0

Vous devez indiquer la mise en cache externe à SQL Server car il gérera la procédure/cache de données pour vous. Si les données sont demandées assez souvent, elles seront soit dans le cache de données SQL Server, soit éventuellement dans le cache du sous-système IO (cache SAN par exemple). Veillez à ne pas effectuer une optimisation prématurée sans données instrumentales réelles pour indiquer que vous avez un problème de performances. Vous pouvez vous attendre au pire des cas, mais vous n'avez aucun moyen de savoir si un cache codé personnalisé sera plus rapide que ce que vous remplacez, puisque vous n'avez pas de temps à comparer. – Andrew

0

Le serveur SQL est optimisé pour effectuer plusieurs lectures simultanées. Le seul moment où vous pouvez rencontrer un blocage est si vous avez beaucoup d'opérations de mise à jour se produisant sur la même table que vous essayez d'accéder. Cependant, si tel est le cas, vous pouvez utiliser le nolock ou même définir le niveau d'isolation de la transaction sur READ UNCOMMITTED.

Maintenant, en ce qui concerne votre question de filetage. SQL Server utilise quelque chose appelé fibres, qui sont comme un sous-thread. Vous ne verrez donc pas nécessairement la même mise à l'échelle des threads de processeur que vous attendez dans un environnement multiprocesseur. Alors que le serveur SQL peut accéder à un certain nombre de threads, un nombre maximum de fibres peut également être utilisé.C'est pourquoi vous pouvez avoir des milliers de clients accédant au même serveur en même temps sur des boîtes même minuscules.

Si vous voulez vraiment entrer dans la programmation de thread/fibre, vous devrez trouver un bon gars de SQL Server qui a vraiment l'impression que c'est compliqué. Il suffit de réaliser que le serveur sql est optimisé pour cela et vous n'avez pas besoin de le tester de quelque manière que ce soit car il a déjà été prouvé avec des outils que vous ne pourrez probablement pas recréer.