SQL代码比C#代码更快吗?

Dra*_*ško 20 c# sql sql-server

几个月前,我开始在这家编程公司工作.他们使用的一种做法是在SQL而不是C#中尽可能多地完成工作.

所以,让我说我有一个写一些文件列表的简单例子:

是这样的:

string SQL = @"
    SELECT f.FileID,
           f.FileName,
           f.FileExtension,
           '/files/' + CAST(u.UserGuid AS VARCHAR(MAX)) + '/' + (f.FileName + f.FileExtension) AS FileSrc,
           FileSize=
           CASE
               WHEN f.FileSizeB < 1048576 THEN CAST(CAST((f.FileSizeB / 1024) AS DECIMAL(6, 2)) AS VARCHAR(8)) + ' KB'
               ELSE CAST(CAST((f.FileSizeB / 1048576) AS DECIMAL(6, 2)) AS VARCHAR(8)) + ' MB'
           END
      FROM Files f
INNER JOIN Users u
        ON f.UserID = u.UserID
";

// some loop for writing results {
//     write...
// }
Run Code Online (Sandbox Code Playgroud)

比这样的事情更快或更好:

string SQL = @"
    SELECT u.UserGuid,
           f.FileID,
           f.FileName,
           f.FileExtension,
           f.FileSizeB
      FROM Files f
INNER JOIN Users u
        ON f.UserID = u.UserID";

// some loop for writing results {
       string FileSrc = "/Files/" + result["UserGuid"] + "/" + result["FileName"] + result["FileExtension"];
       string FileSize = ConvertToKbOrMb(result["FileSizeB"]);  
//     write...
// }
Run Code Online (Sandbox Code Playgroud)

这个特殊的代码并不重要(这只是一些基本的例子)...问题是关于这种事情一般 ......是否更好地加载SQL或"普通"代码?

TFD*_*TFD 20

这只是一个糟糕的编程习惯.您应该分离并隔离程序的不同部分,以便日后维护(想想下一个程序员!)

性能

许多解决方案的DB性能较差,因此大多数开发人员通常会限制SQL数据库访问可能的最小事务.理想情况下,原始数据到人类可读形式的转换应该在最后一点发生.此外,非格式化数据的内存使用量要小得多,虽然内存很便宜,但您不应该浪费它.缓冲,缓存和传输的每个额外字节都占用时间,并减少可用的服务器资源

例如,对于Web应用程序,格式化应该由JSON数据包中的本地JavaScript模板完成.这减少了后端SQL数据库和应用程序服务器的工作量,并减少了需要通过网络传输的数据,所有这些都加快了服务器性能

格式化和本地化

许多解决方案对同一事务有不同的输出需求,例如不同的视图,不同的本地化等.通过将格式化嵌入到SQL事务中,您将不得不为每个本地化创建一个新的事务,这将成为维护的噩梦

格式化的事务也不能用于API接口,你需要另一组API接口的事务,它没有格式化

使用c#你应该使用经过良好测试的模板或字符串处理库,或者至少使用string.Format(),不要在字符串中使用'+'运算符,它非常慢

分担负担

大多数解决方案都有一个DB的多个客户端,因此客户端格式化负载与多个客户端CPU共享,而不是单个SQL数据库CPU

我严重怀疑SQL比c#更快,你应该执行一个简单的基准测试并在此发布结果:-)

  • 想想下一个程序员! (2认同)

Ari*_*tos 13

第二部分可能会慢一点的原因因为您需要从SQL服务器中提取数据并将其提供给C#部分代码,这需要更多时间.

你所做的阅读ConvertToKbOrMb(result["FileSizeB"])越多,总是需要更多的时间,并且还依赖于你的DAL层.我看到一些非常慢的DAL.

如果您将它们留在SQL Server上,您将获得获取数据的额外处理,这就是全部.

根据经验,我的一个优化是始终只提取所需的数据 - 从sql服务器读取的数据越多并将其移动到任何数据(asp.net,console,c#program等),你花费的时间越多它们周围,特别是如果它们是大字符串,或者从字符串到数字进行大量转换.

要回答和直接问题,什么是更快 - 我说你无法比较它们.如果您制作好的代码和良好的查询,它们都会尽可能快.SQL Server还保留了大量的统计信息并改进了返回查询 - c#没有这种部分,那么比较什么呢?

我自己进行一次测试

好吧,我在这里有很多来自项目的数据,并进行快速测试,实际上并不能证明这个数据比另一个快.

我运行了两个案例.

SELECT TOP 100 PERCENT cI1,cI2,cI3 
  FROM [dbo].[ARL_Mesur] WITH (NOLOCK)  WHERE [dbo].[ARL_Mesur].[cWhen] > @cWhen0;

        foreach (var Ena in cAllOfThem)
        {
            // this is the line that I move inside SQL server to see what change on speed
            var results = Ena.CI1 + Ena.CI2 + Ena.CI3;

            sbRender.Append(results);
            sbRender.Append(Ena.CI2);
            sbRender.Append(Ena.CI3);
        }
Run Code Online (Sandbox Code Playgroud)

VS

SELECT TOP 100 PERCENT (cI1+cI2+cI3) as cI1,cI2,cI3 
   FROM [dbo].[ARL_Mesur] WITH (NOLOCK)  WHERE [dbo].[ARL_Mesur].[cWhen] > @cWhen0;


        foreach (var Ena in cAllOfThem)
        {
            sbRender.Append(Ena.CI1);
            sbRender.Append(Ena.CI2);
            sbRender.Append(Ena.CI3);
        }
Run Code Online (Sandbox Code Playgroud)

结果表明速度接近相同.- 所有参数都是double - 读取被优化,我根本没有额外的读取,只是将处理从一个部分移动到另一个部分.

165,766行,以下是一些结果:

Start  0ms  +0ms
 c# processing  2005ms  +2005ms
sql processing  4011ms  +2006ms


Start  0ms  +0ms
 c# processing  2247ms  +2247ms
sql processing  4514ms  +2267ms


Start  0ms  +0ms
 c# processing  2018ms  +2018ms
sql processing  3946ms  +1928ms

Start  0ms  +0ms
c# processing  2043ms  +2043ms
sql processing  4133ms  +2090ms
Run Code Online (Sandbox Code Playgroud)

因此,速度会受到许多因素的影响...我们不知道你的公司问题是什么使得c#比sql处理慢.

  • 我真的没有看到你的观点.如果您只是使用数据读取器循环结果,那么确保这些计算在C#中比TSQL更快.而且您通过网络发送的冗余数据较少.连接的字符串包括重复的常量子字符串,使其比所需的可变部分长. (2认同)

Bra*_*vic 8

作为一般经验法则:SQL用于处理数据,而不是格式化数据的显示方式.

做尽可能多,你可以在SQL,是的,但只要供应这一目标.我只是在那个基础上仔细研究你的"SQL例子".您的"C#示例"看起来更像是对我的责任分离.

话虽如此,请不要太过分,停止在SQL中做一些应该在SQL中完成的事情,比如过滤和加入.例如,INNER JOIN Users u ON f.UserID = u.UserID在C#中重新实现将是一个灾难,性能方面.


至于这种特殊情况下的表现:

我希望"C#示例"(不是所有的 C#,只是这个例子)要快一点,因为......

    f.FileSizeB
Run Code Online (Sandbox Code Playgroud)

...看起来比...更窄

   '/files/' + CAST(u.UserGuid AS VARCHAR(MAX)) + '/' + (f.FileName + f.FileExtension) AS FileSrc,
   FileSize=
   CASE
       WHEN f.FileSizeB < 1048576 THEN CAST(CAST((f.FileSizeB / 1024) AS DECIMAL(6, 2)) AS VARCHAR(8)) + ' KB'
       ELSE CAST(CAST((f.FileSizeB / 1048576) AS DECIMAL(6, 2)) AS VARCHAR(8)) + ' MB'
   END
Run Code Online (Sandbox Code Playgroud)

......应该节省一些网络带宽.并且网络带宽往往比CPU(尤其是客户端CPU)更加稀缺.

当然,您的里程可能会有所不同,但无论哪种方式,性能差异都可能足够小,因此其他问题(例如代码的整体可维护性)变得相对更重要.坦率地说,在这方面,你的"C#例子"对我来说看起来更好.


alb*_*lbe 5

有充分的理由在数据库服务器上尽可能多地做.最大限度地减少必须来回传递的数据量,并为服务器提供优化流程的余地,这是一件好事.

但是,您的示例中并未真正说明这一点.两个进程来回传递尽可能多的数据(可能第一次传递更多),唯一的区别是谁进行计算,可能是客户端做得更好.


Gor*_*off 5

您的问题是关于字符串操作操作是否应该在C#或SQL中完成.我认为这个例子非常小,任何性能增益 - 单向或其他 - 都是无关紧要的.问题是"应该在哪里完成"?

如果代码是应用程序的一部分的"一次性"代码,那么在应用程序级别进行操作非常有意义.如果在整个应用程序中重复此代码,则需要封装它.我认为封装它的最佳方法是使用SQL Server计算列,视图,表值函数或标量函数(在这种情况下计算列更可取).这确保无论在何处调用,相同的处理都相同.

在性能方面,数据库代码和C#代码之间存在关键差异.数据库代码自动并行运行.因此,如果您的数据库服务器是多线程的,那么单独的线程可能同时进行这些字符串操作(没有承诺,这里的关键字是"可能").

通常,在考虑拆分时,您希望最小化来回传递的数据量.这种情况的差异似乎很小.

因此,如果这是具有此逻辑的应用程序中的一个位置,则在应用程序中执行此操作.如果应用程序填充了对此表的需要此逻辑的引用,那么请考虑计算列.如果应用程序在不同的表上有很多类似的请求,那么请考虑一个标量值函数,尽管这可能会影响查询利用并行性的能力.