我的SQL存储过程遇到了一些性能问题。主要是由光标引起的。但我想不出在SQL存储过程中进行循环的任何不同方式。现在有没有办法使用服务器的多个线程来提高程序的性能?
这是我的存储过程的光标:
DECLARE FILE_CURSOR CURSOR FOR
SELECT filenumber
FROM [fmsStage].[dbo].[file]
WHERE relationcode = @relationCode
OPEN FILE_CURSOR
FETCH NEXT FROM FILE_CURSOR INTO @fileID
WHILE @@FETCH_STATUS = 0
BEGIN
/**** Fetch data from outgoinginvoiceline for RelationCode and FileNumber ****/
SET @amount = (SELECT DISTINCT Sum(cnt)
FROM (SELECT Sum([fms].[dbo].[outgoinginvoiceline].[amount]) cnt
FROM [fms].[dbo].[outgoinginvoiceline]
WHERE [fms].[dbo].[outgoinginvoiceline].[filenumber] = CONVERT(NVARCHAR, @fileID)
AND [fms].[dbo].[outgoinginvoiceline].[relationcode] = @relationCode
UNION ALL
SELECT Sum([fmsAir].[dbo].[outgoinginvoiceline].[amount]) cnt
FROM [fmsAir].[dbo].[outgoinginvoiceline]
WHERE [fmsAir].[dbo].[outgoinginvoiceline].[filenumber] = CONVERT(NVARCHAR, @fileID)
AND [fmsAir].[dbo].[outgoinginvoiceline].[relationcode] = @relationCode
UNION ALL
SELECT Sum([fmsProjects].[dbo].[outgoinginvoiceline].[amount]) cnt
FROM [fmsProjects].[dbo].[outgoinginvoiceline]
WHERE [fmsProjects].[dbo].[outgoinginvoiceline].[filenumber] = CONVERT(NVARCHAR, @fileID)
AND [fmsProjects].[dbo].[outgoinginvoiceline].[relationcode] = @relationCode) AS counted)
/**** Get the currency from the database ****/
SET @currency = (SELECT TOP 1 [fms].[dbo].[outgoinginvoiceline].[currency]
FROM [fms].[dbo].[outgoinginvoiceline]
WHERE [fms].[dbo].[outgoinginvoiceline].[filenumber] = CONVERT(NVARCHAR, @fileID)
AND [fms].[dbo].[outgoinginvoiceline].[relationcode] = @relationCode)
/**** If the currency is not EURO then use the currencyrate on it, by default the currencyrate is 1.00 ****/
IF @currency != 'EUR'
BEGIN
SET @currencyRate = (SELECT TOP 1 [fms].[dbo].[outgoinginvoiceline].[rate]
FROM [fms].[dbo].[outgoinginvoiceline]
WHERE [fms].[dbo].[outgoinginvoiceline].[filenumber] = CONVERT(NVARCHAR, @fileID)
AND [fms].[dbo].[outgoinginvoiceline].[relationcode] = @relationCode)
END
/**** If @amount is NULL (empty) then we set it to zero because adding NULL creates issues ****/
IF @amount IS NULL
BEGIN
SET @amount = 0
END
/**** Do the amount times currencyRate ****/
SET @amount = @amount * @currencyRate
/**** Add the new amount to the total previous amount ****/
SET @totalAmount = @totalAmount + @amount
/**** Fetch data from outgoinginvoiceline for RelationCode and FileNumber ****/
SET @amount2 = (SELECT DISTINCT Sum(cnt)
FROM (SELECT Sum([fms].[dbo].[outgoinginvoiceline].[amount]) cnt
FROM [fms].[dbo].[outgoinginvoiceline]
WHERE [fms].[dbo].[outgoinginvoiceline].[filenumber] = CONVERT(NVARCHAR, @fileID)
UNION ALL
SELECT Sum([fmsAir].[dbo].[outgoinginvoiceline].[amount]) cnt
FROM [fmsAir].[dbo].[outgoinginvoiceline]
WHERE [fmsAir].[dbo].[outgoinginvoiceline].[filenumber] = CONVERT(NVARCHAR, @fileID)
UNION ALL
SELECT Sum([fmsProjects].[dbo].[outgoinginvoiceline].[amount]) cnt
FROM [fmsProjects].[dbo].[outgoinginvoiceline]
WHERE [fmsProjects].[dbo].[outgoinginvoiceline].[filenumber] = CONVERT(NVARCHAR, @fileID)) AS counted)
/**** Get the currency from the database ****/
SET @currency2 = (SELECT TOP 1 [fms].[dbo].[outgoinginvoiceline].[currency]
FROM [fms].[dbo].[outgoinginvoiceline]
WHERE [fms].[dbo].[outgoinginvoiceline].[filenumber] = CONVERT(NVARCHAR, @fileID))
/**** If the currency is not EURO then use the currencyrate on it, by default the currencyrate is 1.00 ****/
IF @currency2 != 'EUR'
BEGIN
SET @currencyRate2 = (SELECT TOP 1 [fms].[dbo].[outgoinginvoiceline].[rate]
FROM [fms].[dbo].[outgoinginvoiceline]
WHERE [fms].[dbo].[outgoinginvoiceline].[filenumber] = CONVERT(NVARCHAR, @fileID))
END
/**** If @amount is NULL (empty) then we set it to zero because adding NULL creates issues ****/
IF @amount2 IS NULL
BEGIN
SET @amount2 = 0
END
/**** Do the amount times currencyRate ****/
SET @amount2 = @amount2 * @currencyRate2
/**** Add the new amount to the total previous amount ****/
SET @totalAmount2 = @totalAmount2 + @amount2
FETCH NEXT FROM FILE_CURSOR INTO @fileID
END
答案 0 :(得分:3)
当您应该使用基于集合的解决方案时,您正在使用光标。基于集合的解决方案将类似于:
SELECT
fmsTotalAmount + fmsAirTotalAmount + fmsProjectsTotalAmount TotalAmount,
fmsRelationAmount + fmsAirRelationAmount + fmsProjectsRelationAmount TotalRelationAmount
FROM (
SELECT
SUM(
CASE WHEN fms1.currency != 'EUR'
THEN fms1.Amount * fms1.Rate
ELSE ISNULL(fms1.Amount, 0) END) fmsTotalAmount,
SUM(
CASE WHEN fms1.relationcode = @relationCode
THEN
CASE WHEN fms1.currency != 'EUR'
THEN fms1.Amount * fms1.Rate
ELSE ISNULL(fms1.Amount, 0) END
ELSE 0 END) fmsRelationAmount,
SUM(
CASE WHEN fmsAir1.currency != 'EUR'
THEN fmsAir1.Amount * fmsAir1.Rate
ELSE ISNULL(fmsAir1.Amount, 0) END) fmsAirTotalAmount,
SUM(
CASE WHEN fmsProjects1.relationcode = @relationCode
THEN
CASE WHEN fmsProjects1.currency != 'EUR'
THEN fmsProjects1.Amount * fmsAir1.Rate
ELSE ISNULL(fmsProjects1.Amount, 0) END
ELSE 0 END) fmsAirRelationAmount,
SUM(
CASE WHEN fmsProjects1.currency != 'EUR'
THEN fmsProjects1.Amount * fmsAir1.Rate
ELSE ISNULL(fmsProjects1.Amount, 0) END) fmsProjectsTotalAmount,
SUM(
CASE WHEN fmsProjects1.relationcode = @relationCode
THEN
CASE WHEN fmsProjects1.currency != 'EUR'
THEN fmsProjects1.Amount * fmsProjects1.Rate
ELSE ISNULL(fmsProjects1.Amount, 0) END
ELSE 0 END) fmsProjectsRelationAmount
FROM [fmsStage].[dbo].[file] f
LEFT JOIN [fms].[dbo].[outgoinginvoiceline] fms1 ON
fms1.filenumber = CONVERT(NVARCHAR, f.filenumber)
LEFT JOIN [fmsAir].[dbo].[outgoinginvoiceline] fmsAir1 ON
fmsAir1.filenumber = CONVERT(NVARCHAR, f.filenumber)
LEFT JOIN [fmsProjects].[dbo].[outgoinginvoiceline] fmsProjects1 ON
fmsProjects1.filenumber = CONVERT(NVARCHAR, f.filenumber)
) a
虽然在没有看到您的架构/数据的情况下很难检查这是否正确。
要理解这一点,请从基表开始:
SELECT *
FROM [fmsStage].[dbo].[file] f
LEFT JOIN [fms].[dbo].[outgoinginvoiceline] fms1 ON
fms1.filenumber = CONVERT(NVARCHAR, f.filenumber)
LEFT JOIN [fmsAir].[dbo].[outgoinginvoiceline] fmsAir1 ON
fmsAir1.filenumber = CONVERT(NVARCHAR, f.filenumber)
LEFT JOIN [fmsProjects].[dbo].[outgoinginvoiceline] fmsProjects1 ON
fmsProjects1.filenumber = CONVERT(NVARCHAR, f.filenumber)
总和相当明显(这不能处理货币转换):
SELECT SUM(ISNULL(fms1.Amount, 0)) fmsAmount, SUM(ISNULL(fmsAir1 .Amount, 0) fmsAirAmount --etc., etc.
FROM [fmsStage].[dbo].[file] f
LEFT JOIN [fms].[dbo].[outgoinginvoiceline] fms1 ON
fms1.filenumber = CONVERT(NVARCHAR, f.filenumber)
然后了解case语句,它处理货币转换并按关系代码过滤:
SELECT
fms1.Amount,
CASE WHEN fms1.currency != 'EUR'
THEN fms1.Amount * fms1.Rate
ELSE ISNULL(fms1.Amount, 0) END AmountValue,
CASE WHEN fms1.relationcode = @relationCode
THEN
CASE WHEN fms1.currency != 'EUR'
THEN fms1.Amount * fms1.Rate
ELSE ISNULL(fms1.Amount, 0) END
ELSE 0 END AmountValueOnlyIfSameRelation
FROM [fmsStage].[dbo].[file] f
LEFT JOIN [fms].[dbo].[outgoinginvoiceline] fms1 ON
fms1.filenumber = CONVERT(NVARCHAR, f.filenumber)
然后你将它们组合在一起。