Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/27.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 如何解决存储过程中的性能问题?_Sql_Sql Server_Tsql - Fatal编程技术网

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

Sql 如何解决存储过程中的性能问题?,sql,sql-server,tsql,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

如何在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

您可以通过将SELECT*更改为SELECT 1来实现这一点。也许会有帮助

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


您可以采取措施避免重新读取表以获取输出值

插入后 插入到公共目录中。[CustomerxxxIds]

使用SCOPE_IDxxx获取新创建的代理项密钥

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

通过更新和/或插入,可以使用输出功能获取值

这避免了在调用最后一个select语句以获得所需的输出值时重新读取该语句

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

下面是一个使用输出进行插入和更新的简单但完整的Northwind数据库示例

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


你说它占用大量内存是什么意思?看到执行计划中出现集群,我有一种不愉快的感觉,尤其是与insert结合使用时……执行计划中没有占用内存的操作符。您需要EntityType、CustomerId上的索引-这可能可以简化too@BartHofland-那时你会有很多不愉快的感觉。每次使用聚集索引插入到表中时,您都会看到这样的情况。@BartHofland-现有记录在插入时不会进行物理重新排列,以使它们进入完全未分割的聚集索引键顺序。如果页面上有记录需要进入的空间,则会将记录写入其中,并且只有插槽数组可能会更新为按键顺序指向页面上的行。如果页面上没有空间,将从文件中的任何位置分配一个新页面作为页面拆分并链接到链接列表中。这与用于非聚集索引的过程完全相同。如果它有效果,它可能只是边缘。这是错误的。SQL Server将忽略exist条件中使用的查询的select子句中的任何内容。如果不存在,您甚至可以执行从…中选择1/0。。。。并获得结果,就像从中选择1/0一样。。。你会得到一个被零除的错误。请不要编写没有描述它的功能的大代码块。这段代码以什么方式更好/更快/性能更好?你改变了什么?为什么要更改它?因为您需要entityid,所以我们从一开始就收集,以减少操作数量。如果没有记录,它将为空,我们将使用entityid=1插入,因为在代码中插入的值为0,然后添加一个。这里我们直接插入一个并保存更新操作。现在,如果有一条记录,我添加一条,然后更新并保存最后一个选择,这不是必需的,用这种方式代替4个操作检查,然后插入,然后更新,然后选择我们只使用两个检查,然后插入。在update的情况下,它将被检查,然后updateThis与原始查询的语义不完全相同。原始查询将立即更新刚刚插入的EntityId,因此现在需要将其作为1插入。更新分支也是错误的。它需要将行中的EntityId增加1-没有理由认为所有行中的EntityId都是相同的-您不将其作为1插入-您的值中有一个硬编码常量0。因此,您的重写行为并不相同。我没有提到任何关于身份的事情。你是说你的身份。这是一个函数,不是全局变量。你写的是范围标识和@标识的混合,这是完全不同的事情。2.EntityId显然不是和identity列—因为代码会对其进行更新。无法更新标识列。我修复了作用域标识语法。最初的问题看起来有点混乱,因此为什么我给出了指向这些特性的指针以避免重读即使有语法修复,这个答案仍然是错误的——因为EntityId不是标识列。如果EntityId不是标识,那么可以对这两种情况使用输出。
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