构建大型SQL行集并在.NET中使用

时间:2011-11-22 12:40:21

标签: c# .net sql-server sql-server-2005 .net-3.5

看看这个伪造的模式(请注意这个的简化,所以请尽量不要过多地评论模式本身的“可行性”)。假设指数在FK上就位。

 TABLE Lookup (
     Lookup_ID int not null PK
     Name nvarchar(255) not null
 )

 TABLE Document (
     Document_ID int not null PK
     Previous_ID null FK REFERENCES Document(Document_ID)
 )

 TABLE Document_Lookup (
     Document_ID int not null FK REFERENCES Document(Document_ID)
     Lookup_ID int not null FK REFERENCES Lookup(Lookup_ID)
 )

卷:文档,4百万行,其中90%具有空的Previous_ID字段值;查找,6000行,附加到每个文档20的平均查找,给出Document_Lookup 80百万行。

现在,.NET服务具有表示Lookup行的结构,如下所示: -

 struct Lookup
 {
      public int ID;
      public string Name;
      public List<int> DocumentIDs;
 }

并且查找行存储在Dictionary<int, Lookup>中,其中键是查找ID。这里重要的一点是,这个字典应该包含Lookup被至少一个文档引用的条目,即列表DocumentIDs应该具有Count&gt; 0

我的任务是高效填充此词典。所以简单的方法是: -

  SELECT dl.Lookup_ID, l.Name, dl.Document_ID
  FROM Document_Lookup dl
  INNER JOIN Lookup l ON l.Lookup_ID = dl.Lookup_ID
  INNER JOIN Document d ON d.Document_ID = dl.Lookup_ID
  WHERE d.Previous_ID IS NULL
  ORDER BY dl.Lookup_ID, dl.Document_ID

然后可以使用它来相当有效地填充字典。

问题基础行集交付(TDS?)是否执行某些优化?在我看来,对数据进行去规范化的查询非常常见,因此字段值从一行到下一行不会发生变化的可能性很高,因此通过不发送没有发送字段值的字段来进行视频化是有意义的。改变了。有谁知道这样的优化是否到位?(Optomisation似乎不存在)。

我可以用什么更复杂的查询来消除重复(我特意想到重复名称值)?我听说过这样一个“嵌套行集”,可以生成那种东西吗?会更高效吗?我如何在.NET中访问它?

我会执行两个查询;一个填充Lookup字典,然后填充第二个填充ditionary列表。然后我会添加代码来淘汰未使用的Lookup entires。但是想象一下,我的预测错误,Lookup最终只有一百万行,实际上只有四分之一被任何文件引用?

2 个答案:

答案 0 :(得分:1)

  • 只要名称在实践中相对较短,可能就没有必要进行优化。

  • 最简单的优化是将其拆分为两个查询,一个用于获取名称,另一个用于获取Document_ID列表。 (如果能够更容易地填充数据结构,则可以按其他顺序)。

示例:

/*First get the name of the Lookup*/
select distinct dl.Lookup_ID, l.Name
FROM Document_Lookup dl 
INNER JOIN Lookup l ON l.Lookup_ID = dl.Lookup_ID 
INNER JOIN Document d ON d.Document_ID = dl.Lookup_ID 
WHERE d.Previous_ID IS NULL 
ORDER BY dl.Lookup_ID, dl.Document_ID 

/*Now get the list of Document_IDs for each*/
SELECT dl.Lookup_ID, dl.Document_ID 
FROM Document_Lookup dl 
INNER JOIN Lookup l ON l.Lookup_ID = dl.Lookup_ID 
INNER JOIN Document d ON d.Document_ID = dl.Lookup_ID 
WHERE d.Previous_ID IS NULL 
ORDER BY dl.Lookup_ID, dl.Document_ID 
  • 您可以使用各种技巧将它们按到一张桌子上,但我建议这些不值得。

  • 您正在考虑的层次结构行是MSDASHAPE OLEDB提供程序。他们可以按照您的建议行事,但会限制您使用可能不是您想要的SQL的OLEDB提供程序。

  • 最后请仔细考虑XML

例如:

select
  l.lookup_ID as "@l", 
  l.name as "@n",
  (
    select dl.Document_ID as "node()", ' ' as "node()" 
    from Document_Lookup dl where dl.lookup_ID = l.lookup_ID for xml path(''), type
  ) as "*"
  from Lookup l
  where l.lookup_ID in (select dl.lookup_ID from Document_Lookup dl)
  for xml path('dl')

返回:

<dl l="1" n="One">1 2 </dl>
<dl l="2" n="Two">2 </dl>

答案 1 :(得分:0)

当您询问&#34;嵌套行集&#34;你指的是使用DbDataReader.NextResult()方法吗?

如果您的查询有两个&#34;输出&#34; (两个select语句返回一个单独的结果集),你可以使用DbDataReader.Next()循环第一个,当返回&#34; false&#34;然后你可以调用DbDataReader.NextResult()然后再次使用DbDataReader.Next()继续。

var reader = cmd.ExecuteReader();
  while(reader.Read()){
    // load data
  }

  if(reader.NextResult()){
    while(reader.Read()){
      // lookup record from first result

      // load data from second result
    }
  }

我经常这样做以减少类似情况下的重复数据并且效果非常好:

SELECT * FROM tableA WHERE [condition]
SELECT * FROM tableB WHERE EXISTS (SELECT * FROM tableA WHERE [condition] AND tableB.FK = tableA.PK)

免责声明:我没有尝试使用与您一样大的结果集。

这样做的缺点是你需要一种方法将第二个结果集映射到第一个结果集,使用哈希表或顺序列表。