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

时间:2014-02-23 21:33:16

标签: 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...
// }

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

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...
// }

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

7 个答案:

答案 0 :(得分:20)

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

<强>性能

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

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

格式化和本地化

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

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

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

分担负担

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

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

答案 1 :(得分:13)

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

ConvertToKbOrMb(result["FileSizeB"])所做的阅读次数越多,总是需要花费更多时间,而且还要依赖于DAL图层。我看到一些DAL真的很慢。

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

从经验来看,我的一个优化总是只提取所需的数据 - 你从sql server读取的数据越多,并将其移动到任何地方(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);
        }

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);
        }

结果显示速度接近相同。 - 所有参数均为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

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

答案 2 :(得分:8)

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

在SQL中尽可能多地做,是的,但只有只要它服务于那个目标。我只是在那个基础上仔细研究你的“SQL例子”。您的“C#示例”看起来更清晰地将责任分离给我。

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


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

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

    f.FileSizeB

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

   '/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

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

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

答案 3 :(得分:5)

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

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

答案 4 :(得分:5)

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

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

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

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

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

答案 5 :(得分:4)

这实际上取决于你正在做什么。

不要忘记SQL CLR。有许多操作,T-SQL代码只是速度较慢。

答案 6 :(得分:2)

通常在生产环境中,数据库基础结构层的两倍,有时是应用程序层的三倍。

此外,对于针对数据库本机运行的SQL代码,将具有在应用程序上运行SQL代码并通过数据库驱动程序传递的SQL代码的强大优势。