Par exemple, si je clique sur les vues dynamiques sys pour sélectionner un plan de requête spécifique, puis-je insérer ce plan de requête dans le cache de plan d'une autre base de données, qui exécute la même requête exacte? (Je sais que la requête est hachée et comparée pour déterminer quand générer un nouveau plan, donc dans mon exemple, je m'assurerais que la requête est exactement le même caractère par caractère.)
Ok, c'est donc la réponse à votre question, mais vous voulez probablement savoir pourquoi.
Différentes bases de données peuvent avoir des données différentes et nécessitent donc des plans différents.
Supposons que vous restaurez la base de données WideWorldImporters
sur le même serveur [~ # ~] deux fois [~ # ~] (Appelons-le WWI_1
Et WWI_2
). Vous avez deux bases de données identiques. SQL Server peut éventuellement créer un plan et l'utiliser dans des requêtes pour les deux bases de données.
Mais le problème est que, dès l'instant où ces deux bases de données sont mises en ligne, leurs fourches de "similitude". Ils peuvent être modifiés indépendamment. Même s'ils conservent le même schéma, leurs données peuvent changer indépendamment. Ainsi, SQL Server doit considérer les bases de données indépendamment lors de la compilation des plans. WWI_1
Pourrait avoir différents statistiques de WWI_2
, Ce qui pourrait entraîner des plans différents. Pour que SQL Server utilise le même plan pour les deux bases de données, SQL Server devrait garder une trace des différences après le bifurcation - ce qui serait plus compliqué et plus coûteux que la simple compilation/maintenance de plans séparés.
Imaginons que vous êtes une société de logiciels et hébergez des logiciels pour vos clients. Chaque client obtient sa propre base de données. Dans votre environnement d'hébergement, vous pouvez avoir des centaines de bases de données sur chaque serveur, où chaque base de données a un schéma identique, mais des données uniques à chaque client.
Un client a une base de clients avec 95% de clients en Californie. L'interrogation de la table d'adresses pour tous les clients en Californie entraînerait une table - scan.
-- For CustomerA this query returns 95% of the table, so it scans
SELECT CustomerID
FROM dbo.Addresses
WHERE StateCode = 'CA';
Un client différent a une clientèle qui est répartie uniformément dans tous les États américains, et a également une activité internationale importante. Un pourcentage relativement faible de clients vient de Californie. Dans ce cas, l'interrogation de la table d'adresses pour tous les clients en Californie entraînerait une table - chercher.
-- For CustomerB this query returns <1% of the table, so it seeks
SELECT CustomerID
FROM dbo.Addresses
WHERE StateCode = 'CA';
Requêtes identiques, sur des bases de données au schéma identique, avec des plans radicalement différents en raison de statistiques différentes. Même si ces deux bases de données ont été restaurées à l'origine à partir de la même sauvegarde source, SQL Server devra compiler des plans distincts.
Il ne suffit pas que les deux requêtes soient 100% identiques et que le schéma soit 100% identique. Un plan réutilisé basé uniquement sur ces critères pourrait être très faux - et donc SQL Server ne le fera pas.
Euh ... en quelque sorte.
Utilisons le même exemple "vous êtes une société de logiciels et un logiciel hôte pour vos clients". Vous souhaitez forcer le même plan sur chaque base de données hébergée, indépendamment de ce que SQL Server veut faire. Vous pouvez utiliser un plan guide et appliquer les mêmes instructions à chaque base de données unique sur le serveur. Ce n'est pas tout à fait la même chose que "insérer [un] plan de requête dans le cache de plan d'une autre base de données" ... mais ce serait pratiquement la même chose.
Quelque chose comme SELECT COUNT(*) FROM dbo.SomeTable
serait assez simple pour utiliser le même plan sur les deux bases de données, non? Non, pas même alors!
Créons un exemple:
Voici un code pour le faire:
CREATE DATABASE Sample1;
GO
USE Sample1
GO
CREATE TABLE dbo.SomeTable (
SomeID int IDENTITY(1,1) PRIMARY KEY CLUSTERED,
StuffType int,
OtherStuff varchar(100),
INDEX OtherStuff(OtherStuff)
);
GO
SET NOCOUNT ON;
INSERT INTO dbo.SomeTable (StuffType,OtherStuff)
SELECT object_id%50,
name
FROM sys.objects;
GO 1000
BACKUP DATABASE Sample1 TO DISK = '/var/opt/mssql/data/Sample1.bak' WITH INIT;
RESTORE DATABASE Sample2 FROM DISK = '/var/opt/mssql/data/Sample1.bak'
WITH MOVE 'Sample1' TO '/var/opt/mssql/data/Sample2.mdf',
MOVE 'Sample1_log' TO '/var/opt/mssql/data/Sample2_log.ldf';
Maintenant, faisons cette requête COUNT(*)
. Même plan sur les deux? Oui! Sur mon ordinateur portable, il effectue le comptage en scannant le PK en cluster
SQL Server choisit d'analyser le PK car il est plus petit. L'index non clusterisé est plus grand car il est très fragmenté.
La maintenance des index se fait maintenant sur la base de données Sample1
(Mais pas sur Sample2
). Quelqu'un reconstruit les index sur dbo.SomeTable
:
ALTER INDEX ALL ON Sample1.dbo.SomeTable REBUILD;
Comment cela affecte-t-il le plan de requête?
Sur Sample1
, L'index non clusterisé est désormais Nice & compact. Il est plus petit que le PK. L'analyse de l'index non clusterisé sera le bon choix sur `Sample1 car il est plus petit, moins d'E/S et sera plus rapide.
Sur Sample2
, Scanner le PK est le bon choix, car il est plus petit, moins d'E/S et donc plus rapide.
Schémas identiques avec des données identiques, le second étant issu d'une sauvegarde récente du premier. Ces deux requêtes ont des plans d'exécution différents, mais les deux ont également le plan de requête meilleur pour leur scénario.