Je travaille sur une requête pour me donner tous les objets de base de données qui dépendent directement ou indirectement à n'importe quel niveau, à une table appelée dbo.tblborder
, qui est fortement dépend de.
Toutefois, cette question en particulier est liée au plan de requête de cette requête, car je vois des avertissements dans le plan de requête (dans les opérateurs de tri distincts) deux types d'avertissements, dont une liée au déversement à TEMPDB et l'autre avertissement relatif à la conversion de Types de données et estimation de la cardinalité.
la requête et le plan de requête sont plus bas, après les images.
Comme je m'occupe des objets système, comment puis-je découvrir lesquels je dois mettre à jour les statistiques?
Ou autrement, comment sortir de cet avertissement sur le plan de requête?
Et en ce qui concerne la conversion de type de données, vous pouvez-il faire quelque chose pour éviter cela et le problème de l'estimation de la cardinalité?
Un drapeau de trace peut-être?
c'est une base de données de 600 Go, j'aimerais trouver toutes les dépendances sur une table spécifique, premier niveau à lui seul me montre 325 objets, mais ce n'est pas une requête que je manquerais tous les jours. Je suis intéressé à éliminer ces avertissements, mais ce n'est pas une question de vie et de mort.
1ère image de l'avertissement sur le déversement sur TEMPDB:
2e photo de l'avertissement sur le déversement sur TEMPDB:
3ème avertissement - liée à la conversion de type de données et peut affecter l'estimation de la cardinalité :
;WITH Radhe AS (
SELECT DISTINCT
s2.object_id,
Name=SCHEMA_NAME(S2.schema_id) + '.' + S2.Name,
ObjectType = S2.Type,
DependsOn = s1.object_id,
DependsOn_Name=SCHEMA_NAME(S1.schema_id) + '.' + S1.Name,
0 as Level
FROM sys.sysdepends DP
INNER JOIN sys.objects S1
ON S1.object_id = DP.DepID
INNER JOIN sys.objects S2
ON S2.object_id = DP.ID
WHERE S1.object_id = OBJECT_ID('DBO.tblborder')
UNION ALL
SELECT
s2.object_id,
Name=SCHEMA_NAME(S2.schema_id) + '.' + S2.Name,
ObjectType = S2.Type,
DependsOn = s1.object_id,
DependsOn_Name=s1.Name,
Level + 1
FROM sys.sysdepends DP
INNER JOIN Radhe S1
ON S1.object_id = DP.ID
INNER JOIN sys.objects S2
ON S2.object_id = DP.DepID
WHERE Level < 100
AND S1.object_id <> S2.object_id
AND S2.object_id <> OBJECT_ID('DBO.tblborder')
)
SELECT DISTINCT *
FROM Radhe
ORDER BY LEVEL DESC, DependsOn_Name
Voici le plan de requête pour cette requête
Après avoir mis à jour les statistiques de cette façon (à partir de Comment mettre à jour les statistiques pour les tables système d'une base de données ):
DECLARE @TSql NVARCHAR(MAX) = ''
SELECT @TSql = @TSql + 'UPDATE STATISTICS sys.' + o.name + ' WITH FULLSCAN;' + CHAR(13) + CHAR(10)
FROM sys.objects o
WHERE o.type in ('S')
ORDER BY o.name
--Verify/test commands.
PRINT @TSql
Les avertissements liés aux déversements TEMPDB sont toujours là, cependant, ils ont changé conformément à l'image ci-dessous:
Rien n'a été dit ou adressé à l'avertissement suivant cependant:
Tapez la conversion dans l'expression (Convertir (Bigint, [BOCSSS2]. [SYS]. [SYSOBJVALU (SYSOBJVALUES]. [VALUE], 0)) Peut affecter "CARDINALITYESTAME" dans le choix de plan de requête, tapez la conversion dans l'expression (Convertir (BOCSSS2] . [SYS]. [SYSOBJVALUES]. [valeur], 0)) peut affecter "cardinalitéestimée" dans le choix de plan de requête
Le Q & A - Comment mettre à jour les statistiques pour les tables système de la base de données est très bon, mais ne semblait pas avoir résolu mon problème ici entièrement, plus aucune adresse au Estimation en cardinalité Avertissement.
Les avertissements que vous voyez viennent probablement de la vue Sys.sysDepends.
Si vous écrivez le script en utilisant
EXEC sys.sp_helptext @objname = N'sys.sysdepends'
La définition a un tas de convertis et d'autres non-sens en cours.
CREATE VIEW sys.sysdepends AS
SELECT
id = object_id,
depid = referenced_major_id,
number = convert(smallint,
case when objectproperty(object_id, 'isprocedure') = 1 then 1 else column_id end),
depnumber = convert(smallint, referenced_minor_id),
status = convert(smallint, is_select_all * 2 + is_updated * 4 + is_selected * 8),
deptype = class,
depdbid = convert(smallint, 0),
depsiteid = convert(smallint, 0),
selall = is_select_all,
resultobj = is_updated,
readobj = is_selected
FROM sys.sql_dependencies
WHERE class < 2
UNION ALL
SELECT -- blobtype dependencies
id = object_id, depid = object_id,
number = convert(smallint, column_id), depnumber = convert(smallint, type_column_id),
status = convert(smallint, 0), deptype = sysconv(tinyint, 1),
depdbid = convert(smallint, 0), depsiteid = convert(smallint, 0),
selall = sysconv(bit, 0), resultobj = sysconv(bit, 0), readobj = sysconv(bit, 0)
FROM sys.fulltext_index_columns
WHERE type_column_id IS NOT NULL
sys.Objects, d'autre part, est assez simple.
CREATE VIEW sys.objects AS
SELECT name,
object_id,
principal_id,
schema_id,
parent_object_id,
type,
type_desc,
create_date,
modify_date,
is_ms_shipped,
is_published,
is_schema_published
FROM sys.objects$
La définition de vue pour SyS.SysDepends provoque les mêmes avertissements lorsqu'ils sont interrogés seuls .
SELECT *
FROM sys.sysdepends
En général, si vous souhaitez contrôler des fichiers de données et des index et que vous avez une capacité de réglage des performances lorsque vous référencez des vues ou des tables du système, votre meilleur pari est de les jeter dans une table Temp d'abord.
Les avertissements dans les plans de requête ne sont qu'un problème si la requête ne fonctionne pas à un niveau acceptable. Si j'ai une requête qui se termine dans 10 ms, alors pourquoi passer du temps en tant que programmeur essayant de le faire aller plus vite pour faire un avertissement disparaître? En fait, toute requête qui se répandit à TEMPDB lancera un avertissement. Je serais intéressé de voir un système dans lequel les requêtes ne se répandent jamais à Tempdb.
En outre, il existe une variété de causes possibles pour un déversement à TEMPDB. En fait, parfois SQL Server se répandra délibérément à TEMPDB. Selon le système, la mise à jour des statistiques sur les tables sous-jacentes peut être une étape raisonnable pour résoudre le problème. Cependant, cela ne résout pas toujours le problème.
On dirait que vous marchez trop sur le fait que vous devez utiliser les vues du système. Pensez-y comme un code d'écriture contre des vues fournies par un fournisseur que vous ne pouvez pas modifier. Vous pouvez utiliser presque toutes les mêmes techniques d'optimisation que vous pouvez utiliser contre d'autres requêtes. Je pense que vous ne pouvez tout simplement pas créer d'index ou de statistiques sur les tables système cachées.
Erik a déjà couvert votre question sur l'avertissement de conversion de type de données afin que je me concentre sur les autres questions.
Le moyen le plus simple que je connaisse de trouver quels objets système sont utilisés est de délivrer SET STATISTICS IO, TIME ON;
Avant d'exécuter la requête. Par exemple:
SET STATISTICS IO, TIME ON;
SELECT COUNT(*) FROM sys.objects;
-- Table 'sysschobjs'. Scan count 1
UPDATE STATISTICS sys.sysschobjs WITH FULLSCAN;
Comme vous l'avez vécu, cela pourrait ne pas suffire à faire disparaître les déversements. Je soupçonne que le problème ici est que vous avez écrit une requête récursive. L'optimiseur SQL Server Query a souvent du mal à estimer exactement combien de lignes seront retournées par une requête récursive. Pour moi, cela semble être une limitation raisonnable. Cela ressemble à quelque chose qui serait très difficile à modeler.
Peut-être que le problème ici n'est-ce pas qu'il s'agit d'une requête récursive. Quelles autres choses pouvez-vous essayer de faire disparaître le déversement?
1. Mettez des ensembles de résultats intermédiaires importants dans des tables Temps
Les estimations de la cardinalité s'aggravent souvent car les rangées circulent dans le plan de requête. Vous pourrez peut-être placer certains des résultats de la requête dans une table Temp et réfléchir à la table Temp dans la requête à la place. Pour certaines requêtes, vous pouvez obtenir une meilleure performance et des estimations de manière spectaculaire en mettant un petit résultat défini dans une table TEM.
2. Essayez le Legacy CE .
J'ai vu le drapeau de trace 9481 améliorer la performance des requêtes contre les vues du système. Si vous pensez que vous avez un problème d'estimation de la cardinalité, c'est une chose que vous pouvez essayer.
3. Trick SQL Server dans la délivrance d'une subvention de mémoire de requête plus grande.
Dans SQL Server 2016, il est assez facile avec le nouveau min_grant_percent Requête. Sur les anciennes versions, il est un peu plus difficile. Vous auriez besoin d'écrire un code logiquement équivalent qui augmente le nombre estimé de lignes retournées.
4. Réécrivez la requête de sorte qu'une sorte n'est pas nécessaire à la fin
Je n'ai pas regardé votre code pour voir à quel point cela serait difficile, mais je pense que cette suggestion est évidente.
En termes d'autres drapeaux de trace pour vous aider avec les déversements, je ne connais que drapeau de trace 747 , qui est peu susceptible de s'appliquer à votre situation.