2015-03-27 1 views
0

J'ai actuellement une base de données complète des entrées ACL qui ressemble à ceci:Quel est le moyen le plus efficace d'analyser ces lignes de 500k?

ACL database

Je dois aller à travers et analyser la différence entre un nœud racine (comme \\ chrlcltsvr02 \ AYY_LMO \ ClientServices) et c'est des nœuds enfants (ex. \\ chrlcltsvr02 \ AYY_LMO \ ClientServices \ Client1).

J'ai essayé de faire cela en code C# en utilisant un ORM et T-SQL brute comme si (je ne sais en fait que l'ouverture d'une session par ligne est une idée horrible):

foreach (string path in distinctPaths) 
{ 
    using (session = sessionFactory.OpenSession()) 
    { 
     string query; 

     query = String.Format("SELECT DISTINCT UserGroup, AllowDeny, Permissions FROM FilerACLs WHERE FullPath LIKE '{0}'", path.Replace("'", "''")); 

     var parentACLs = session.CreateSQLQuery(query).SetResultTransformer(Transformers.AliasToBean<ShareACLEntry>()).List<ShareACLEntry>(); 

     query = String.Format("SELECT DISTINCT UserGroup, AllowDeny, Permissions FROM FilerACLs WHERE FullPath LIKE '{0}\\%'", path.Replace("'", "''")); 

     var childACLs = session.CreateSQLQuery(query).SetResultTransformer(Transformers.AliasToBean<ShareACLEntry>()).List<ShareACLEntry>(); 

     if (childACLs.Except(parentACLs, comparer).ToList().Count > 0) 
      Console.WriteLine("{0} has diffs!", path); 
    } 
} 

Et enfin, comparer les données obtenues pour voir si les nœuds enfants diffèrent du nœud racine. Par différence, je veux dire si j'ai une liste de contrôle d'accès pour le groupe "CLT-AD \ Accès total partagé-CHRL" avec un contrôle total autorisé sur le nœud parent et non sur le nœud enfant, je voudrais noter que le ACL existe sur l'enfant mais pas sur le parent. Malheureusement, ce processus est beaucoup trop lent pour analyser les 500 000 rangées dans une période de temps décente. Je voudrais savoir si quelqu'un a une idée pour déterminer efficacement s'il y a des différences dans les données - que ce soit en utilisant directement T-SQL, une fonction SQL CLR, ou un meilleur algorithme en général.

Veuillez me faire savoir si une clarification est nécessaire.

Merci!

EDIT

Depuis que je suis devenu une bonne quantité de haine sur cette question me laisse re-préciser exactement ce que je cherche moins les approches ont échoué, je l'ai indiqué plus haut.

J'ai récemment effectué une analyse sur environ 1 000 dossiers partagés sur un serveur Windows. Cette analyse est récursive depuis le répertoire de niveau supérieur tout le long de la hiérarchie des dossiers et, pour chaque dossier, elle enregistre une ligne pour chaque liste de contrôle d'accès.

La base de données ressemble donc à la capture d'écran ci-dessus. Ce que je dois faire est de tirer un rapport de cette base de données qui détaille la différence (ou même s'il y en a) entre les ACL enregistrés à partir d'un répertoire de niveau supérieur et les ACL enregistrées pour n'importe quel répertoire sous ce répertoire de premier niveau.

J'espère que cela a plus de sens.

+2

ce n'est pas du code C# c'est TSQL. Qu'entendez-vous par "différences"? – Jodrell

+0

Désolé j'ai oublié de mentionner que j'ai utilisé un ORM pour convertir le résultat du SQL brut en un objet CLR. – slashp

+0

Vous devrez montrer votre code C# pour nous faire savoir si ce que vous faites là peut être traduit en une solution purement SQL, ou pour voir si l'algorithme peut être amélioré. – juharr

Répondre

2

Voici quelques TSQL,

DECLARE @parentFullPath NVARCHAR(260) = N'\\chrlcltsvr02\AYY_LMO\ClientServices'; 
DECLARE @childFullPath NVARCHAR(260) = N'\\chrlcltsvr02\AYY_LMO\ClientServices\Client1'; 

SELECT 
      [UserGroup], 
      [AllowDeny], 
      [Permissions] 
    FROM 
      [ACLs] 
    WHERE 
      [FullPath] = @childFullPath 
EXCEPT 
SELECT 
      [UserGroup], 
      [AllowDeny], 
      [Permissions] 
    FROM 
      [ACLs] 
    WHERE 
      [FullPath] = @parentFullPath; 

Il peut ou ne peut pas faire ce que votre besoin, il est difficile de le dire.


Pour trouver toutes les paires d'enfants de parents,

WITH [paths] AS (
SELECT 
      [FullPath] 
    FROM 
      [ACLs] 
    GROUP BY 
      [FullPath]) 
SELECT 
      [P].[FullPath] [ParentFullPath], 
      [C].[FullPath] [ChildFullPath] 
    FROM 
      [paths] [P] 
     JOIN 
      [paths] [C] 
       ON 
         [C].[FullPath] <> [P].[FullPath] 
        AND 
         CHARINDEX([P].[FullPath], [C].[FullPath]) = 1; 

pour que vous puissiez en fait tout faire à la fois, quelque chose comme ça.

WITH [paths] AS (
SELECT 
      [FullPath] 
    FROM 
      [ACLs] 
    GROUP BY 
      [FullPath]) 
SELECT 
      [PC].[ParentFullPath], 
      [PC].[ChildFullPath], 
      [D].[UserGroup], 
      [D].[AllowDeny], 
      [D].[Permissions] 
    FROM (
      SELECT 
         [P].[FullPath] [ParentFullPath], 
         [C].[FullPath] [ChildFullPath] 
       FROM 
         [paths] [P] 
        JOIN 
         [paths] [C] 
          ON 
            [C].[FullPath] <> [P].[FullPath] 
           AND 
            CHARINDEX([P].[FullPath], [C].[FullPath]) = 1; 
     ) [PC] 
CROSS APPLY 
(
SELECT 
      [UserGroup], 
      [AllowDeny], 
      [Permissions] 
    FROM 
      [ACLs] 
    WHERE 
      [FullPath] = [PC].[ChildFullPath] 
EXCEPT 
SELECT 
      [UserGroup], 
      [AllowDeny], 
      [Permissions] 
    FROM 
      [ACLs] 
    WHERE 
      [FullPath] = [PC].[ParentFullPath] 
) [D]; 

En fin de compte, si vous voulez que ce code fonctionne efficacement, vous aurez besoin de normaliser votre schéma quelque peu. Tant que la relation parent-enfant n'existe que par inférence par comparaison de chaînes, l'opération sera relativement lente.

+0

Ceci est très proche de ce que j'ai essayé dans T-SQL - je suis curieux comme s'il y avait un moyen de passer à travers tous les chemins distincts que j'ai - donc en réponse à votre commentaire sur mes questions, je suppose que le les nœuds racine seraient tirés en utilisant un DISTCINT sur le chemin complet et les nœuds enfants devraient être calculés à partir de là. – slashp

+0

Cela fonctionne parfaitement pour extraire les données que je recherche. Merci pour votre aide Jodrell !!! – slashp

1

Si vous voulez le faire pour toute la liste en une fois, vous pouvez écrire une expression SQL (par exemple en utilisant substring()) pour obtenir get_parent_path_from_child_path et exécuter une structure SQL suivante. Il n'est pas clair dans votre question comment séparer un parent d'un enfant dans un cas général. Je vous donne juste un code filaire.

(
SELECT -- parents 
      [UserGroup], 
      [AllowDeny], 
      [Permissions], 
      [FullPath] as parent_path 
    FROM 
      [ACLs] 
    WHERE add a filter for parents here 

minus 
SELECT -- children 
      [UserGroup], 
      [AllowDeny], 
      [Permissions], 
      get_parent_path_from_child_path([FullPath]) as parent_path 
    FROM 
      [ACLs] 
    WHERE add a filter for children here 

) 
union 
(
SELECT -- children 
      [UserGroup], 
      [AllowDeny], 
      [Permissions], 
      get_parent_path_from_child_path([FullPath]) as parent_path 
    FROM 
      [ACLs] 
    WHERE add a filter for children here 
minus 
SELECT -- parents 
      [UserGroup], 
      [AllowDeny], 
      [Permissions], 
      [FullPath] as parent_path 
    FROM 
      [ACLs] 
    WHERE add a filter for parents here 

)