在过去的几个月中,我遇到了多种情况,传统的sql SP正在返回一个主要由冗余信息构成的表。
示例:
从......
中选择CustomerID,CustomerEmail,CustomerAddress,InventoryLineItem,ShipQty返回:
55 a@b.com 723 StreetName InvLineItem#1 45
55 a@b.com 723 StreetName InvLineItem#2 42
55 a@b.com 723 StreetName InvLineItem#3 1
55 a@b.com 723 StreetName InvLineItem#4 5
55 a@b.com 723 StreetName InvLineItem#5 200
55 a@b.com 723 StreetName InvLineItem#6 7045
(前3个字段永不改变)
由于我是该项目的唯一开发人员,因此我开始将其分为两个选择语句。 (我也在接收.NET代码)
从....
中选择CustomerID,CustomerEmail,CustomerAddressReturns: 55 a@b.com 723 Streetname <-- 1 record
从....选择InventoryLineItem,ShipQty 返回:
LineItem#1 45
LineItem#2 42
LineItem#3 1
等
显然,.NET中生成的数据集较小,但是在select语句中有时候10个字段总是在所有情况下都完全相同,这真的让我感到困惑。有些查询甚至可能会返回数以千计的记录。
我觉得我在这里做的是正确的事,但是我再也不是SQL专业人士了。
我有理由避免这种做法吗?
提前感谢您的时间。
答案 0 :(得分:3)
嗯,我在这里的重要答案是,如果您将输出提供给报告框架(例如SSRS),那么多个表将使您的生活变得困难 - 报告框架非常擅长取消非规范化结果并将其处理为漂亮的报道。
就性能而言,不,你没有理由避免多个结果集离开sproc。只要你在客户端使用DataReader和.NextResult(),IMO就是你的黄金。
答案 1 :(得分:3)
我一直使用多个结果集。
在你的情况下,我会有2个,一个用于标题,一个用于细节。 通常,客户端无论如何都必须提取标题:当客户端不能像那样使用它时,我为什么要压扁它(例如膨胀)?
我使用的其他区域是网页。每次调用数据库都有足够的数据用于屏幕上的一个操作或弹出窗口(现在假设没有缓存)。
比如说,一个标题行,5,详细说明行+查找行,用于详细行的下拉列表。
另一个原因是表现。可以调整SQL查询,可以调整C#代码,但不能进行往返(例如web&lt; - &gt;数据库)。
答案 2 :(得分:3)
如果您的客户端使用从存储过程返回的数据可以正确处理多个结果集,那么不,绝对没有理由不使用它们。
它们有几个优点,正如您已经指出的那样:
- 减少传输的数据量
- 保持规范化,不存在不必要的数据重复
- 相比于必须调用两个单独的存储过程(一个用于标题,一个用于详细信息数据),保存到服务器的往返行程
总而言之 - 去吧! :-)对我来说似乎是个好主意。
马克
答案 3 :(得分:2)
我认为你对冗余数据的想法是正确的 它是流经网络的额外数据。
您可能正在使用与SELECTing相同的参数调用存储过程。
e.g。 GetCustomerOrders 'ALFKI'
- 可能会返回
ALFKI | ALFA客户| OID001 ......
ALFKI | ALFA客户| OID002 ......
ALFKI | ALFA客户| OID003 ......
因此,您可以避免将作为参数传递给存储过程的字段的SELECTion。
编辑:再想一想,可能会有另一个存储过程 - 它将返回客户相关信息。发票相关程序将返回给定客户ID的发票数据。
答案 4 :(得分:1)
我发现存储过程返回的内容的一致性非常重要,但您肯定会看到系统存储过程没有一致性(请考虑sp_help)。
所以它真的取决于你所追求的是什么,以及你的客户端代码是否能够处理它。任何时候你想要早期绑定,或者你有一个客户端会询问存储过程它将返回什么(例如任何报告客户端,或ORM系统,如LINQ),那么你可能会遇到麻烦。如果您正在使用.Net代码,并且您希望每次都能看到不同的结果集结构,那么它可能不是什么大问题。
在一天结束时,如果你有大量的列在某些情况下可能是空的,这可能会让你在客户端更灵活,但这一切都取决于你想把工作放在哪里。 / p>
我个人的偏好是拥有一个总是相同形状的结果集。但话说回来,我也会考虑将其放在一个表值函数中,这样我就能以更灵活的方式处理结果(例如分组等)。我发现存储过程非常适合客户端需要调用的东西,但是如果我想要以不同的方式处理东西,我宁愿使用视图或表值函数来生成它(就像从系统中移动一样)存储过程到DMV,微软一段时间后退了。)
罗布
答案 5 :(得分:1)
我最担心的是,如果您的数据库是高度事务性的,那么两个查询之间的数据可能无法正确关联。换句话说,第二个查询可能包含不在第一个查询中的记录(因为它们是在第一个查询完成时添加的),因此您不知道它们的相关数据。当然,这也可以反向工作,在第二个查询运行之前删除第一个查询的记录。
答案 6 :(得分:1)
这听起来不适用于你的情况,但是如果存储过程被另一个存储过程调用,那么在第一个存储过程之后返回的任何数据集将是“不可见的” - 也就是说,不可访问 - 呼叫程序。难以执行INSERT ... EXECUTE ...语句。 (当然,这些集将返回给调用应用程序。)