解析这 50 万行的最有效方法是什么?
What's the most efficient way to parse these 500k rows?
我目前有一个充满 ACL 条目的数据库,如下所示:
我需要检查并解析根节点(如 \\chrlcltsvr02\AYY_LMO\ClientServices)和它的 child 节点(例如 \\chrlcltsvr02\AYY_LMO\ClientServices\Client1)之间的区别。
我曾尝试使用 ORM 和原始 T-SQL 在 C# 代码中执行此操作(事实上我知道每行打开一个会话是一个可怕的想法):
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);
}
}
最后比较结果数据,看看 child 节点是否与根节点不同。
不同的是,我的意思是如果我有一个组 "CLT-AD\Full Access Shared-CHRL" 的 ACL,允许完全控制 parent 节点而不是 child 节点,我想请注意,ACL 存在于 child 而不是 parent。
不幸的是,这个过程太慢了,无法在任何合适的时间内解析 500k 行。
我想知道是否有人有想法来有效地确定数据中是否存在差异——直接使用 T-SQL、SQL CLR 函数或更好的方法一般算法。
如果需要澄清,请告诉我。
谢谢!
编辑
因为我对这个问题有相当多的仇恨,让我 re-clarify 正是我正在寻找的减去我上面概述的失败方法。
我最近对 Windows 服务器上的约 1,000 个共享文件夹进行了扫描。此扫描从顶级目录一直递归到文件夹层次结构,并且为每个文件夹为每个 ACL 记录一行。
因此数据库看起来像上面的屏幕截图。
我需要做的是从该数据库中提取一份报告,详细说明从顶级目录记录的 ACL 与为该顶级目录下的任何目录记录的 ACL 之间的差异(甚至是否存在差异) .
希望这更有意义。
这是一些 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;
它可能会或可能不会满足您的要求,这很难说。
要找到所有的父子对,
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;
所以您实际上可以一次完成所有操作,就像这样。
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];
最终,如果您希望这段代码 运行 有效,您需要对您的模式进行一些规范化。只要父子关系仅通过字符串比较推断存在,这将是一个相对较慢的操作。
如果你想一次完成整个列表,你可以写一个 SQL 表达式(例如使用 substring())到 get_parent_path_from_child_path 和 运行 下面SQL 结构。从您的问题中不清楚在一般情况下如何将 parent 与 child 分开。所以我只是给你一个线框代码。
(
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
)
我目前有一个充满 ACL 条目的数据库,如下所示:
我需要检查并解析根节点(如 \\chrlcltsvr02\AYY_LMO\ClientServices)和它的 child 节点(例如 \\chrlcltsvr02\AYY_LMO\ClientServices\Client1)之间的区别。
我曾尝试使用 ORM 和原始 T-SQL 在 C# 代码中执行此操作(事实上我知道每行打开一个会话是一个可怕的想法):
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);
}
}
最后比较结果数据,看看 child 节点是否与根节点不同。
不同的是,我的意思是如果我有一个组 "CLT-AD\Full Access Shared-CHRL" 的 ACL,允许完全控制 parent 节点而不是 child 节点,我想请注意,ACL 存在于 child 而不是 parent。
不幸的是,这个过程太慢了,无法在任何合适的时间内解析 500k 行。
我想知道是否有人有想法来有效地确定数据中是否存在差异——直接使用 T-SQL、SQL CLR 函数或更好的方法一般算法。
如果需要澄清,请告诉我。
谢谢!
编辑
因为我对这个问题有相当多的仇恨,让我 re-clarify 正是我正在寻找的减去我上面概述的失败方法。
我最近对 Windows 服务器上的约 1,000 个共享文件夹进行了扫描。此扫描从顶级目录一直递归到文件夹层次结构,并且为每个文件夹为每个 ACL 记录一行。
因此数据库看起来像上面的屏幕截图。
我需要做的是从该数据库中提取一份报告,详细说明从顶级目录记录的 ACL 与为该顶级目录下的任何目录记录的 ACL 之间的差异(甚至是否存在差异) .
希望这更有意义。
这是一些 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;
它可能会或可能不会满足您的要求,这很难说。
要找到所有的父子对,
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;
所以您实际上可以一次完成所有操作,就像这样。
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];
最终,如果您希望这段代码 运行 有效,您需要对您的模式进行一些规范化。只要父子关系仅通过字符串比较推断存在,这将是一个相对较慢的操作。
如果你想一次完成整个列表,你可以写一个 SQL 表达式(例如使用 substring())到 get_parent_path_from_child_path 和 运行 下面SQL 结构。从您的问题中不清楚在一般情况下如何将 parent 与 child 分开。所以我只是给你一个线框代码。
(
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
)