2016-12-30 88 views
1

我写了一个与我的Visual Basic .NET代码完全相同的存储过程。现在我已经对它们进行了基准测试。使用while循环和for循环。但是,两者都给我带来了更糟糕的结果,即使用我的Visual Basic .NET代码。有什么办法改善这种代码的性能:存储过程提高性能

DECLARE @RelationCode nvarchar(50) 
DECLARE @CompanyName nvarchar(256) 
DECLARE @IncomingInvoice decimal(18, 2) 
DECLARE @OutgoingInvoice decimal(18, 2) 
DECLARE @Profit decimal(18, 2) 
DECLARE @RelationTable as TABLE (RELATIONCODE nvarchar(10), COMPANY nvarhar(120)) 

INSERT INTO @RelationTable (RELATIONCODE, COMPANY) SELECT [fms].[dbo].[Relation].[RELATIONCODE], [fms].[dbo].[Relation].[COMPANYNAME] FROM [fms].[dbo].[Relation] 

/* Result table */ 
DECLARE @RESULTTABLE TABLE (RelationCode nvarchar(50), Companyname nvarchar(256), IncomingInvoice nvarchar(50), OutgoingInvoice nvarchar(50), profit nvarchar(50)) 

WHILE EXISTS(SELECT * FROM @RelationTable) 
BEGIN 
SELECT TOP 1 @RelationCode = RELATIONCODE, @CompanyName = COMPANY FROM @RelationTable 

    SELECT fmsTotalAmountIncoming INTO TempIncomingAmounts FROM (
      SELECT SUM(CASE WHEN fms1.currency != 'EUR' 
       THEN fms1.amount * fms1.rate 
      ELSE ISNULL(fms1.amount, 0) END) fmsTotalAmountIncoming 
    FROM [fms].[dbo].[file] f 
     INNER JOIN [fms].[dbo].[incominginvoiceline] fms1 ON 
     fms1.filenumber = CONVERT(NVARCHAR, f.filenumber) 
    WHERE f.RELATIONCODE = @RelationCode 
    ) a 

    SELECT fmsTotalAmountOutgoing INTO TempOutgoingAmounts FROM (
      SELECT SUM(CASE WHEN fms1.currency != 'EUR' 
       THEN fms1.amount * fms1.rate 
      ELSE ISNULL(fms1.amount, 0) END) fmsTotalAmountOutgoing 
    FROM [fms].[dbo].[file] f 
     INNER JOIN [fms].[dbo].[outgoinginvoiceline] fms1 ON 
     fms1.filenumber = CONVERT(NVARCHAR, f.filenumber) 
    WHERE f.RELATIONCODE = @RelationCode 
    ) a 
    SET @IncomingInvoice = (SELECT fmsTotalAmountIncoming FROM [fms].[dbo].[TempIncomingAmounts]) 
     SET @OutgoingInvoice = (SELECT fmsTotalAmountOutgoing FROM [fms].[dbo].[TempOutgoingAmounts]) 
     SET @Profit = ((@OutgoingInvoice - @IncomingInvoice)/@OutgoingInvoice) 

     INSERT INTO @RESULTTABLE ([RELATIONCODE], [CompanyName], [IncomingInvoice], [OutgoingInvoice], [Profit]) 
       VALUES (@RelationCode, @CompanyName, @IncomingInvoice, @OutgoingInvoice, @Profit) 

     DROP TABLE [fms].[dbo].[TempIncomingAmounts] 
     DROP TABLE [fms].[dbo].[TempOutgoingAmounts] 

     DELETE FROM @RelationTable WHERE RelationCode = @RelationCode 
    END 

    SELECT * FROM @RESULTTABLE 

我已经基准这一点,下面的结果:

STORED PROCEDURE  VB.NET 
6:54     5:11 
6:20     5:11 
6:19     3:55 
6:43     4:01 

有没有人对如何提高VB.net上述性能的任何线索性能,因为这种方式存储过程是没用的。

+0

存储过程*不*提高错误查询的性能。而不是像这样使用游标或循环(实际上是一种更慢的游标形式),您应该编写适当的查询 –

+0

请发布您的表模式和数据示例。 –

+0

使用正确的工具进行工作。 Sql服务器就是为保存和读取数据而设计的IO设备。计算和其他“业务”逻辑可以在你的应用程序('vb.net')中完成 - 很容易,可以更快地完成(用于加载来自不同表格的数据的'async-await'方法),可读(非常重要)和简单保持。 – Fabio

回答

6

您试图在SQL中复制过程式VB代码。 SQL是基于集合的,并且仅在此基础上执行良好。不知道你的模式是什么,这是大概你的SQL应该像让你需要多大的成果,更快:

; 
WITH invoice (RELATIONCODE, COMPANYNAME, IncomingInvoice, OutgoingInvoice) 
AS (
    SELECT r.[RELATIONCODE], r.[COMPANYNAME], 
    SUM(CASE WHEN fms1.currency != 'EUR' 
      THEN fms1.amount * fms1.rate 
     ELSE ISNULL(fms1.amount, 0) END) AS IncomingInvoice, 
    SUM(CASE WHEN fmso.currency != 'EUR' 
      THEN fmso.amount * fmso.rate 
     ELSE ISNULL(fmso.amount, 0) END) AS OutgoingInvoice 
    FROM [fms].[dbo].[Relation] r 
    LEFT OUTER JOIN [fms].[dbo].[file] f 
    ON f.RELATIONCODE = r.[RELATIONCODE] 
    LEFT OUTER JOIN [fms].[dbo].[incominginvoiceline] fms1 
    ON fms1.filenumber = CONVERT(NVARCHAR, f.filenumber) 
    LEFT OUTER JOIN [fms].[dbo].[outgoinginvoiceline] fmso 
    ON fmso.filenumber = CONVERT(NVARCHAR, f.filenumber) 
    GROUP BY r.[RELATIONCODE], r.[COMPANYNAME] 
) 
SELECT RELATIONCODE, 
    COMPANYNAME, 
    IncomingInvoice, 
    OutgoingInvoice, 
    CASE WHEN OutgoingInvoice > 0 THEN (OutgoingInvoice - IncomingInvoice)/OutgoingInvoice 
    ELSE 0 END AS Profit 
FROM invoice 

即没有循环,if ... else语句,创建,删除然后重新创建永久表等等。只需要一个SQL语句按关系代码和公司名称对结果进行分组。

+0

这个工作起来很快,但是当它除以零时会自行消灭,如何消除它?我得到这个: https://gyazo.com/3d31bacdb4f26a67e61fe027bacf8c6a –

+1

我已经在'SELECT'中添加了一个'CASE'语句来检查分母中的0值,这将避免除0除外。 – strickt01

+0

好吧,但我有很多行缺失,我有4474关系,它给了我1707行,很多关系没有传入或外出发票,如何仍然得到它们?即使它们是NULL –