一次往返执行多个 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 命令的主要内容,如果未能解决你的问题,请参考以下文章

使用多结果集读取数据减少服务器往返,提高性能

使用redis pipeline打包执行多条任务

如何通过一个数据库往返执行两个 EF linq 查询

Redis事务

Pipeline

mysql怎么一次执行多条SQL语句