Performances CTE récursives

8

Besoin d'aide avec les performances CTE récursives. Ci-dessous, CTE fonctionne très lentement car il tente d'extraire les données héréditaires de manière récurrente. La table est grande avec chaque id racine ayant jusqu'à 3 itemid récursifs. Il pourrait y avoir environ 200 000 identifiants racine ou plus. Je sais que les CTE récursifs sont lents pour un énorme ensemble de données car pour chaque rootid dans l'ancre, il serait itemid récursivement.

Schéma:

Create table RootItem (ItemId int primary key, RootIt int , insertdate datetime)

Le tableau ci-dessus contient plus d'un million de lignes.

Requête CTE:

; With rootcte as

( select itemid from RootItem where rootid is null

union all

  select r.itemid as RootId , i.itemid from RootItem i join rootcte r
    on i.rootid = r.itemid
)

Nous ne pouvons pas modifier le schéma de table et utiliser heirarchyid. J'ai aussi essayé la boucle mais c'est trop lent.

Existe-t-il un autre moyen d'optimiser cette requête?

 ; With rootcte as

( select itemid from RootItem where rootid is null

 union all

 select r.itemid as RootId , i.itemid from RootItem i join rootcte r
 on i.rootid = r.itemid
) 
  SELECT  
     Cust.CustomerID  
    , Cust.BusinessName  
    , sCust.RegionCustomerID  
    , ord.OrderID  
    , ord.OrderItemID  
    , prd.ProductCode  
    , rc.itemid
    , rc.rootid 
    , mf.FileID  
FROM  
    vw_Customer Cust  
    INNER JOIN SrcCustomer scust ON Cust.CustomerID = sCust.RegionCustomerID  
    INNER JOIN OrderItem ord ON Cust.MasterCustomerID = ord.MasterCustomerID  
    INNER JOIN Product ON ord.ProductID = Product.ProductID  
    INNER JOIN rootcte rc ON ord.RootOrderId = rc.Rootid   
    INNER JOIN MFolder mf ON mf.mfolderid = rc.itemid  
    INNER JOIN MVersion mv ON mv.mfolderversionid = mf.mfolderid   
    WHERE ord.IsActive = 1  and product.IsSelling = 1 and mf.fileid in (23,45,29)
     and mv.isdeleted = 'N' 

Je travaille également avec BI group pour changer la logique de requête et filtrer les données dans cte lui-même de déplacer quelques jointures et critères vers cte .. Merci pour tous les commentaires.

njvds
la source
2
pourquoi avez-vous besoin de toutes les hiérarchies? Il ne devrait pas y avoir d'endroit où se trouver quelque part, vous ne devez donc calculer que les enregistrements que vous avez l'intention d'utiliser. Vous n'avez certainement pas besoin de créer des millions de hiérarchies à chaque fois que vous exécutez cela.
HLGEM
Il s'agit d'un rapport collatéral qui est exécuté environ 5-6 fois en heures ouvrables et doit être exécuté sur l'ensemble de données entier. J'aurais pu précharger les données si les données étaient statiques ou n'étaient pas insérées souvent, mais dans ce cas, des opérations DML fréquentes s'exécutent sur cette table dans DB.
njvds
Quels index avez-vous à cette table?
ypercubeᵀᴹ
ItemID est la clé primaire et il y a aussi un index non clusterisé sur itemid et rootid.
njvds
1
Vous devez montrer la requête que vous utilisez réellement. Comme c'est le cas maintenant, tout ce que vous faites est un moyen compliqué de renvoyer tous les ItemID de la table. Le CTE récursif n'ajoute aucune valeur.
Mikael Eriksson

Réponses:

3

Vous dites que la hiérarchie est modifiée. Vraisemblablement pendant que cette opération est en cours, il y a une certaine quantité de blocage qui se produit alors?

Même si la hiérarchie change, les racines des éléments changent-elles?

Avez-vous regardé le temps qu'il faudrait pour créer la table de mappage de la racine à l'élément et l'indexer?

Je voudrais voir le plan d'exécution pour voir ce qui se passe - le CTE devrait être mis en file d'attente, mais en tant que table matérialisée et indexée manuellement, il pourrait mieux fonctionner dans les étapes ultérieures.

Même avec une activité intense, il me semble que quelqu'un doit être bloqué si les opérations DML modifient les données que ce processus lit.

J'envisagerais donc fortement de prendre un instantané de la hiérarchie.

De plus, vous avez un certain nombre d'autres jointures INNER - vous devez vérifier s'il s'agit en fait des CTE et s'il manque des index pour rendre ces jointures efficaces. Le plan d'exécution devrait vous le dire.

Vous semblez avoir quelques éléments dans la clause WHERE qui pourraient aider à réduire certaines opérations (et déterminer quels index pourraient être les meilleurs)), mais il est difficile de le dire sans regarder le plan d'exécution ou les index.

Cade Roux
la source
Pourquoi une opération DML bloquerait-elle le SELECT? SQL Server est-il toujours aussi limité?
a_horse_with_no_name
@a_horse_with_no_name msdn.microsoft.com/en-us/library/ms173763.aspx c'est possible mais l'utilisateur a mentionné qu'il y a une forte activité, il devrait donc réfléchir à sa stratégie
Cade Roux