一次往返执行多个 SQL 命令
Posted
技术标签:
【中文标题】一次往返执行多个 SQL 命令【英文标题】:Execute multiple SQL commands in one round trip 【发布时间】:2011-01-21 03:17:34 【问题描述】:我正在构建一个应用程序,我想将多个查询批处理到一个数据库的单次往返中。例如,假设单个页面需要显示用户列表、组列表和权限列表。
所以我已经存储了过程(或者只是简单的 sql 命令,如“从用户中选择 *”),我想执行其中的三个。但是,要填充这一页,我必须进行 3 次往返。
现在我可以编写一个存储过程(“getUsersTeamsAndPermissions”)或执行一个 SQL 命令“select * from Users;exec getTeams;select * from Permissions”。
但我想知道是否有更好的方法来指定在一次往返中执行 3 次操作。好处包括更容易进行单元测试,并允许数据库引擎并行化查询。
我正在使用 C# 3.5 和 SQL Server 2008。
【问题讨论】:
如果这是 ASP.Net,并且 DB 服务器就在 Web 服务器旁边(或者它是一个仅限内部的应用程序),那么这很可能是一个过早的优化...... @Earlz,要么是过早的优化,要么是对其他一些设计问题的修复。 每次我回来阅读这个问题时,我都会对有多少人阅读我的简单示例感到好笑,我弥补了这个问题,并假设他们比我更了解我的应用程序的性能特征。 请在此处阅读我的回答:***.com/a/49687720/538387 【参考方案1】:类似于this。该示例可能不是很好,因为它没有正确处理对象,但您明白了。这是一个清理后的版本:
using (var connection = new SqlConnection(ConnectionString))
using (var command = connection.CreateCommand())
connection.Open();
command.CommandText = "select id from test1; select id from test2";
using (var reader = command.ExecuteReader())
do
while (reader.Read())
Console.WriteLine(reader.GetInt32(0));
Console.WriteLine("--next command--");
while (reader.NextResult());
【讨论】:
+1 获取不错的代码示例。这就是我在一个命令中使用多个 sql 语句的问题中所说的。 谢谢你,一直在寻找处理连接和命令的正确方法:)【参考方案2】:您提到的单个多部分命令和存储过程选项是两个选项。您不能以使它们在数据库上“并行化”的方式来执行它们。但是,这两个选项都会导致单次往返,所以你很好。没有办法更有效地发送它们。在 sql server 2005 以后,完全参数化的多部分命令非常有效。
编辑:将有关为什么塞进一个电话的信息。
虽然您不想太在意减少通话次数,但可能有这样做的正当理由。
我曾经被限制在大型机上使用糟糕的 ODBC 驱动程序,每次调用都有 1.2 秒的开销!我是认真的。有时我会在我的数据库调用中塞进一点 extra。不漂亮。 您还可能会发现自己必须在某处配置 sql 查询,而且您不能只进行 3 次调用:它必须是一次。不应该那样,糟糕的设计,但它是。你做你该做的! 当然,有时将多个步骤封装在一个存储过程中会非常好。通常不是为了节省往返行程,而是为了更紧凑的交易、获取新记录的 ID、限制权限、提供封装等等。【讨论】:
单次往返是最重要的考虑因素。【参考方案3】:一次往返对三次确实会更有效。问题是它是否值得麻烦。整个 ADO.Net 和 C# 3.5 工具集和框架都反对您尝试做的事情。 TableAdapters、Linq2SQL、EF,所有这些都喜欢处理简单的 one-call==one-resultset 语义。因此,您可能会因为试图击败框架而降低工作效率。
我想说,除非您有一些认真的测量结果表明您需要减少往返次数,否则请弃权。如果您确实最终需要这样做,那么使用存储过程至少提供一种 API 语义。
但如果您的查询确实是您发布的内容(即选择所有用户、所有团队和所有权限)那么你显然有在减少往返之前要炸大得多的鱼……首先减少结果集。
【讨论】:
这些都是我脑补的。 +1 告诉我不要打扰。相信我,在我开始做这件事之前我会做很多其他事情,因为 Web 服务器和数据库服务器彼此非常接近。 但是我认为 MSTF 应该实现一些对象(也许 ObjectContext 中应该有一个 IDisposable 属性,当输入该属性时,将立即执行所有累积的查询,将每个结果集设置为强类型。【参考方案4】:我这个this 链接可能会有所帮助。
考虑使用至少相同的连接打开;根据here 所说,打开连接几乎是Entity-Framework 性能成本的最高领导者。
【讨论】:
连接池几乎总是会确保你只打开一个物理连接,所以通常你不需要担心打开多个连接的性能成本。【参考方案5】:首先,3 次往返并不是什么大问题。如果您在谈论 300 次往返,那将是另一回事,但对于仅 3 次往返,我认为这是一个过早优化的情况。 p>
也就是说,我这样做的方式可能是使用 SQL 执行 3 个存储过程:
exec dbo.p_myproc_1 @param_1 = @in_param_1, @param_2 = @in_param_2
exec dbo.p_myproc_2
exec dbo.p_myproc_3
然后,您可以像直接执行多个行集一样遍历返回的结果集。
【讨论】:
【参考方案6】:建立一个临时表?将所有结果插入临时表,然后select * from @temp-table
如,
@temptable=....
select @temptable.field=mytable.field from mytable
select @temptable.field2=mytable2.field2 from mytable2
等等...只有一次访问数据库,虽然我不确定它实际上是否更有效。
【讨论】:
这将进行 4 次往返 ;)以上是关于一次往返执行多个 SQL 命令的主要内容,如果未能解决你的问题,请参考以下文章