如何解决存储过程中的性能问题?

时间:2019-06-13 12:27:04

标签: sql sql-server tsql

如何在SP中使用SQL查询获得更好的性能?它有很多内存使用情况。如果您在我的执行面板下面查看,将会发现:

IF NOT EXISTS(SELECT * FROM Common.[CustomerxxxIds] WHERE xyzType = @xyzType AND CustomerId = @CustomerId)[/code]

有大量的内存使用情况。我该如何减少呢?

ALTER PROCEDURE [Common].[SaveCustomerxxxIds] 
(
    @xyzType    NVARCHAR(128),
    @CustomerId INT,
    @xxxId  INT OUTPUT
)
AS
BEGIN
    SET NOCOUNT ON;

    IF NOT EXISTS(SELECT * FROM Common.[CustomerxxxIds] WHERE xxxType = @xxxType AND CustomerId = @CustomerId)
    BEGIN
        INSERT INTO Common.[CustomerxxxIds]
                    ([xxxId]
                    ,[CustomerId]
                    ,[xxxType])
                VALUES
                    (0
                    ,@CustomerId
                    ,@xxxType)
    END

    UPDATE  Common.[CustomerxxxIds]
    SET     [xxxId] = ([xxxId]) + 1
    WHERE   [xxxType] = @xxxType
            AND CustomerId = @CustomerId

    SELECT  @xxxId = xxxId
    FROM    Common.[CustomerxxxIds]
    WHERE   [xxxType] = @xxxType
            AND CustomerId = @CustomerId
END

3 个答案:

答案 0 :(得分:2)

您可以采取一些措施来避免对表进行“重新读取”​​以获得输出值。

在插入之后 (插入Common。[CustomerxxxIds])

使用SCOPE_IDxxx()获取新创建的代理密钥。

以上内容仅适用于IDxxx列。根据您的问题,您实际上可能没有IDxxx列。

请参见

https://docs.microsoft.com/en-us/sql/t-sql/functions/scope-idxxx-transact-sql?view=sql-server-2017

.........

通过UPDATE和/或INSERT,您可以使用OUTPUT功能来获取值。

https://docs.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql?view=sql-server-2017

这避免了最后一个select语句(即我所说的“重新读取”​​),以获得所需的输出值。

显然,完全删除SELECT语句将提高性能。

..

下面是一个简单但完整的罗斯文数据库示例,该示例将OUTPUT用于INSERT和UPDATE

SELECT 'Before' as Looksie, [ShipperID]
      ,[CompanyName]
      ,[Phone]
  FROM [Northwind].[dbo].[Shippers]

  --
  DECLARE @MyInsertAuditTable table( AuditShipperID INT,  
                           AuditCompanyName nvarchar(40),  
                           AuditPhone nvarchar(24));  
INSERT [Northwind].[dbo].[Shippers] (CompanyName , Phone )
    OUTPUT INSERTED.ShipperID, INSERTED.CompanyName, INSERTED.Phone  
        INTO @MyInsertAuditTable  (AuditShipperID, AuditCompanyName , AuditPhone )

SELECT TOP 1
    --(SELECT MAX(ShipperID) + 1 from dbo.Shippers )
     'Shipper' + LEFT(CONVERT(VARCHAR(38), NEWID()), 12)
    , '(555) 555-5555'
    FROM sys.objects

--Display the result set of the table variable.  
SELECT AuditShipperID, AuditCompanyName, AuditPhone FROM @MyInsertAuditTable;  

  DECLARE @MyUpdateAuditTable table( AuditShipperID INT,  
                           AuditCompanyName nvarchar(40),  
                             AuditOldPhone nvarchar(24),
                           AuditNewPhone nvarchar(24));  

UPDATE [Northwind].[dbo].[Shippers] 

SET Phone = '(777) 555-7777'

OUTPUT inserted.ShipperID,  inserted.CompanyName ,
       deleted.Phone,  
       inserted.Phone
INTO @MyUpdateAuditTable ( AuditShipperID, AuditCompanyName, AuditOldPhone , AuditNewPhone)
FROM [Northwind].[dbo].[Shippers]  shippers
JOIN @MyInsertAuditTable insAudit on shippers.ShipperID = insAudit.AuditShipperID

SELECT * from @MyUpdateAuditTable



SELECT 'After' as Looksie, [ShipperID]
      ,[CompanyName]
      ,[Phone]
  FROM [Northwind].[dbo].[Shippers]

  --

结果

Looksie ShipperID   CompanyName Phone
Before  1   Speedy Express  (503) 555-9831
Before  2   United Package  (503) 555-3199
Before  3   Federal Shipping    (503) 555-9931

..

AuditShipperID  AuditCompanyName    AuditPhone
9               Shipper3C062D46-EEA (555) 555-5555

...

AuditShipperID  AuditCompanyName    AuditOldPhone   AuditNewPhone
9               Shipper3C062D46-EEA (555) 555-5555  (777) 555-7777

..

Looksie ShipperID   CompanyName Phone
After   1           Speedy Express  (503) 555-9831
After   2           United Package  (503) 555-3199
After   3           Federal Shipping    (503) 555-9931
After   9           Shipper3C062D46-EEA (777) 555-7777

答案 1 :(得分:0)

您可以通过将SELECT *更改为SELECT 1来实现。可能有帮助

IF NOT EXISTS (SELECT 1 FROM Common.[CustomerxxxIds] 
               WHERE xyzType = @xyzType AND CustomerId = @CustomerId)

答案 2 :(得分:-1)

尝试一下

    ALTER PROCEDURE [Common].[SaveCustomerxxxIds] 
(
    @xyz NVARCHAR(128),
    @CustomerId INT,
    @xxxId   INT OUTPUT
)
AS
BEGIN
    set @xxxId=null
    --Get xxxId
    SELECT @xxxId=[xxxId] FROM Common.[CustomerxxxIds] WHERE xyz = @xyz AND CustomerId = @CustomerId
    --If @xxxId means no record we should insert 
    if (@xxxId is null)
        begin 
            --When insert we always insert xxxId as 0 then update to one then we collect the  value (one) from db and return it.
            --Better set value directly as one insert it to DB and return it as one. Instead of insert, update, select
            --just insert
            set @xxxId = 1
           INSERT INTO Common.[CustomerxxxIds]
                            ([xxxId]
                            ,[CustomerId]
                            ,[xyz])
                        VALUES
                            (@xxxId
                            ,@CustomerId
                            ,@xyz)
        end 
    else
        begin
            --If we have the value we add one to it update the record and return it.
            --better than update table then select. 
            --We already have the value we add one to it then update table and return the value we have 
            set @xxxId+=1
            UPDATE  Common.[CustomerxxxIds]   SET     [xxxId] = @xxxId
            WHERE   [xyz] = @xyz       AND CustomerId = @CustomerId
        END
end