Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/80.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何提高sql server中while循环插入的性能?_Sql_Sql Server_Performance_Tsql_Stored Procedures - Fatal编程技术网

如何提高sql server中while循环插入的性能?

如何提高sql server中while循环插入的性能?,sql,sql-server,performance,tsql,stored-procedures,Sql,Sql Server,Performance,Tsql,Stored Procedures,这是我的SQL查询。它从临时表中插入了几乎6500多行。但它需要15分钟以上。我该如何改进这一点?谢谢 ALTER proc [dbo].[Process_bill] @userid varchar(10), @remark nvarchar(500), @tdate date , @pdate date as BEGIN IF OBJECT_ID('tempdb.dbo..#temptbl_bill', 'U') IS NOT NULL DROP TABLE #temptbl_

这是我的SQL查询。它从临时表中插入了几乎6500多行。但它需要15分钟以上。我该如何改进这一点?谢谢

ALTER proc [dbo].[Process_bill]
@userid varchar(10),
@remark nvarchar(500),
@tdate date ,
@pdate date
as

BEGIN 


IF OBJECT_ID('tempdb.dbo..#temptbl_bill', 'U') IS NOT NULL
    DROP TABLE #temptbl_bill; 

CREATE TABLE #temptbl_bill (
   RowID int IDENTITY(1, 1), 
   ------------

)

// instert into temp table

DECLARE @NumberRecords int, @RowCounter int
DECLARE @batch INT
SET @batch   = 300
SET @NumberRecords = (SELECT COUNT(*) FROM #temptbl_bill)
SET @RowCounter = 1

SET NOCOUNT ON  

BEGIN TRANSACTION

WHILE @RowCounter <= @NumberRecords
BEGIN

declare @clid int
declare @hlid int
declare @holdinNo nvarchar(150)
declare @clientid nvarchar(100)
declare @clientName nvarchar(50)
declare @floor int
declare @radius nvarchar(50)
declare @bill money 
declare @others money
declare @frate int
declare @due money
DECLARE @fine money
DECLARE @rebate money

IF @RowCounter > 0 AND ((@RowCounter % @batch = 0) OR (@RowCounter = @NumberRecords))           
BEGIN                   
    COMMIT TRANSACTION
    PRINT CONCAT('Transaction #', CEILING(@RowCounter/ CAST(@batch AS FLOAT)), ' committed (', @RowCounter,' rows)');
    BEGIN TRANSACTION
END;

 // multiple select 


// insert to destination  table

Print 'RowCount -' +cast(@RowCounter as varchar(20))  + 'batch -' + cast(@batch as varchar(20))

SET @RowCounter = @RowCounter + 1;

END

COMMIT TRANSACTION

PRINT CONCAT('Transaction #', CEILING(@RowCounter/ CAST(@batch AS FLOAT)), ' committed (',
@RowCounter,' rows)');

SET NOCOUNT OFF 

DROP TABLE #temptbl_bill

END

GO

正如在评论中所说,循环是完全没有必要的。提高任何循环性能的方法是完全删除它。循环是SQL中的最后手段

据我所知,您的插入可以用一条语句编写:

INSERT tbl_bill(clid, hlid, holdingNo,ClientID, ClientName, billno, date_month, unit, others, fine, due, bill, rebate, remark, payment_date, inserted_by, inserted_date) 
SELECT  clid = c.id, 
        hlid = h.id,
        h.holdinNo ,
        c.cliendID, 
        clientName = CAST(c.clientName AS NVARCHAR(50)), 
        BillNo = CONCAT(h.holdinNo, MONTH(@tdate), YEAR(@tdate)),
        date_month = @tDate,
        unit = 0,
        others = CASE WHEN h.hfloor = 0 THEN rs.frate * (h.hfloor - 1) ELSE 0 END, 
        fine = bs.FineRate * b.Due / 100, 
        due  = b.Due, 
        bill = @bill,   -- This is declared but never assigned
        rebate = bs.rebate,
        remark = @remark,
        payment_date = @pdate,
        inserted_by = @userid, 
        inserted_date = GETDATE()
FROM    (   SELECT  id, clientdID, ClientName
            FROM    tbl_client 
            WHERE   status = 1
        ) AS c
        INNER JOIN 
        (   SELECT  id, holdinNo, [floor], connect_radius
            FROM    tx_holding 
            WHERE   status = 1 
            AND     connect_radius <> '0' 
            AND     type = 'Residential'
        ) AS h
            ON c.id = h.clid
        LEFT JOIN tbl_radius_setting AS rs
            ON rs.radius= CONVERT(real,h.connect_radius) 
            AND rs.status = 1 
            AND rs.type = 'Non-Govt.'
        LEFT JOIN tbl_bill_setting AS bs
            ON bs.Status = 1
        LEFT JOIN 
        (   SELECT  hlid,
                    SUM(netbill) AS Due
            FROM    tbl_bill AS b
            WHERE   date_month < @tdate  
            AND     (b.ispay = 0 OR b.ispay IS NULL) 
            GROUP BY hlid
        ) AS b
            ON b.hlid = h.id
WHERE   NOT EXISTS 
        (   SELECT  1 
            FROM    tbl_bill AS tb 
            WHERE   EOMONTH(@tdate) = EOMONTH(date_month)       
            AND     tb.holdingNo = h.holdinNo
            AND     (tb.update_by IS NOT NULL OR tb.ispay=1)
        );
要获取@tdate的月份第一天,则几乎与forumla相同,但将月份添加到1900年2月1日,而不是1月1日,以获取下一个月的开始:

DATEADD(MONTH, DATEDIFF(MONTH, '19000201', @tdate), '19000201') 
因此,以下是:

DECLARE @Tdate DATE = '2019-10-11';
SELECT  DATEADD(MONTH, DATEDIFF(MONTH, '19000101', @tdate), '19000101'),
        DATEADD(MONTH, DATEDIFF(MONTH, '19000201', @tdate), '19000201');
将分别于10月1日和11月1日返回。将其放回原始查询将提供:

WHERE   NOT EXISTS 
        (   SELECT  1 
            FROM    tbl_bill AS tb 
            WHERE   date_month >= DATEADD(MONTH, DATEDIFF(MONTH, '19000101', @tdate), '19000101'),
            AND     date_month < DATEADD(MONTH, DATEDIFF(MONTH, '19000201', @tdate), '19000201')
            AND     tb.holdingNo = h.holdinNo
            AND     (tb.update_by IS NOT NULL OR tb.ispay=1)
        );

正如在评论中所说,循环是完全没有必要的。提高任何循环性能的方法是完全删除它。循环是SQL中的最后手段

据我所知,您的插入可以用一条语句编写:

INSERT tbl_bill(clid, hlid, holdingNo,ClientID, ClientName, billno, date_month, unit, others, fine, due, bill, rebate, remark, payment_date, inserted_by, inserted_date) 
SELECT  clid = c.id, 
        hlid = h.id,
        h.holdinNo ,
        c.cliendID, 
        clientName = CAST(c.clientName AS NVARCHAR(50)), 
        BillNo = CONCAT(h.holdinNo, MONTH(@tdate), YEAR(@tdate)),
        date_month = @tDate,
        unit = 0,
        others = CASE WHEN h.hfloor = 0 THEN rs.frate * (h.hfloor - 1) ELSE 0 END, 
        fine = bs.FineRate * b.Due / 100, 
        due  = b.Due, 
        bill = @bill,   -- This is declared but never assigned
        rebate = bs.rebate,
        remark = @remark,
        payment_date = @pdate,
        inserted_by = @userid, 
        inserted_date = GETDATE()
FROM    (   SELECT  id, clientdID, ClientName
            FROM    tbl_client 
            WHERE   status = 1
        ) AS c
        INNER JOIN 
        (   SELECT  id, holdinNo, [floor], connect_radius
            FROM    tx_holding 
            WHERE   status = 1 
            AND     connect_radius <> '0' 
            AND     type = 'Residential'
        ) AS h
            ON c.id = h.clid
        LEFT JOIN tbl_radius_setting AS rs
            ON rs.radius= CONVERT(real,h.connect_radius) 
            AND rs.status = 1 
            AND rs.type = 'Non-Govt.'
        LEFT JOIN tbl_bill_setting AS bs
            ON bs.Status = 1
        LEFT JOIN 
        (   SELECT  hlid,
                    SUM(netbill) AS Due
            FROM    tbl_bill AS b
            WHERE   date_month < @tdate  
            AND     (b.ispay = 0 OR b.ispay IS NULL) 
            GROUP BY hlid
        ) AS b
            ON b.hlid = h.id
WHERE   NOT EXISTS 
        (   SELECT  1 
            FROM    tbl_bill AS tb 
            WHERE   EOMONTH(@tdate) = EOMONTH(date_month)       
            AND     tb.holdingNo = h.holdinNo
            AND     (tb.update_by IS NOT NULL OR tb.ispay=1)
        );
要获取@tdate的月份第一天,则几乎与forumla相同,但将月份添加到1900年2月1日,而不是1月1日,以获取下一个月的开始:

DATEADD(MONTH, DATEDIFF(MONTH, '19000201', @tdate), '19000201') 
因此,以下是:

DECLARE @Tdate DATE = '2019-10-11';
SELECT  DATEADD(MONTH, DATEDIFF(MONTH, '19000101', @tdate), '19000101'),
        DATEADD(MONTH, DATEDIFF(MONTH, '19000201', @tdate), '19000201');
将分别于10月1日和11月1日返回。将其放回原始查询将提供:

WHERE   NOT EXISTS 
        (   SELECT  1 
            FROM    tbl_bill AS tb 
            WHERE   date_month >= DATEADD(MONTH, DATEDIFF(MONTH, '19000101', @tdate), '19000101'),
            AND     date_month < DATEADD(MONTH, DATEDIFF(MONTH, '19000201', @tdate), '19000201')
            AND     tb.holdingNo = h.holdinNo
            AND     (tb.update_by IS NOT NULL OR tb.ispay=1)
        );

首先不使用循环可能是一个开始。SQL不是一种编程语言,而是一种查询语言。它擅长基于集合的操作,而不是迭代操作。您是否尝试过使用单语句insert进行insert。。选择@对不起,你是说CTE?看看执行计划,看看插入临时表的慢部分在哪里让我的眼睛流血。格式太糟糕了。但现在是学习并开始使用ANSI-92样式联接的时候了。他们已经存在超过25年了。但这里最大的问题首先是循环。这应该是一个单insert语句,而不是一行一行地执行。首先不使用循环可能是一个开始。SQL不是一种编程语言,而是一种查询语言。它擅长基于集合的操作,而不是迭代操作。您是否尝试过使用单语句insert进行insert。。选择@对不起,你是说CTE?看看执行计划,看看插入临时表的慢部分在哪里让我的眼睛流血。格式太糟糕了。但现在是学习并开始使用ANSI-92样式联接的时候了。他们已经存在超过25年了。但这里最大的问题首先是循环。这应该是一个单一的insert语句,而不是一行一行地执行。哇。@GarethD非常感谢。我知道这是个糟糕的问题。我需要更多的学习。这个完整的查询不是我写的。不管怎样,我正在检查你的代码。再次感谢你们的辛勤工作和时间。巨大的努力。哇。@GarethD非常感谢。我知道这是个糟糕的问题。我需要更多的学习。这个完整的查询不是我写的。不管怎样,我正在检查你的代码。再次感谢你的辛勤工作和时间。