我正在创建一个临时表 ( #myTable) 并使用游标。当并发用户通过我的应用程序访问游标时,这会产生问题吗?它是否允许我创建具有相同名称的单独临时表?
以下是示例代码:
Open cursor;
Fetch Next from cursor into @Variable_Temp_Table_Name;
Create table #myTable(pk int)
While @@Fetch_Status = 0
Begin
Fetch Next from cursor into @Variable_Temp_Table_Name;
End
Run Code Online (Sandbox Code Playgroud) 我遇到了一个查询的性能问题,我似乎无法理解。
我从游标定义中提取了查询。
此查询需要几秒钟才能执行
SELECT A.JOBTYPE
FROM PRODROUTEJOB A
WHERE ((A.DATAAREAID=N'IW')
AND ((A.CALCTIMEHOURS<>0)
AND (A.JOBTYPE<>3)))
AND EXISTS (SELECT 'X'
FROM PRODROUTE B
WHERE ((B.DATAAREAID=N'IW')
AND (((((B.PRODID=A.PRODID)
AND ((B.PROPERTYID=N'PR1526157') OR (B.PRODID=N'PR1526157')))
AND (B.OPRNUM=A.OPRNUM))
AND (B.OPRPRIORITY=A.OPRPRIORITY))
AND (B.OPRID=N'GRIJZEN')))
AND NOT EXISTS (SELECT 'X'
FROM ADUSHOPFLOORROUTE C
WHERE ((C.DATAAREAID=N'IW')
AND ((((((C.WRKCTRID=A.WRKCTRID)
AND (C.PRODID=B.PRODID))
AND (C.OPRID=B.OPRID))
AND (C.JOBTYPE=A.JOBTYPE))
AND (C.FROMDATE>{TS '1900-01-01 00:00:00.000'}))
AND ((C.TODATE={TS '1900-01-01 00:00:00.000'}))))))
GROUP BY A.JOBTYPE
ORDER BY A.JOBTYPE
Run Code Online (Sandbox Code Playgroud)
实际的执行计划是这样的。

注意到服务器范围的设置被设置为 MaxDOP 1,我尝试使用 maxdop 设置。
添加OPTION (MAXDOP 0)到查询或更改服务器设置会导致更好的性能和此查询计划。

但是,有问题的应用程序(Dynamics AX)不会执行这样的查询,它使用游标。 …
performance sql-server parallelism cursors microsoft-dynamics query-performance
我有一个奇怪的情况。使用sp_whoisactive我可以看到:
好的,通过这个查询,我可以看到是什么触发了(这个词在英语中存在吗?)它:
SELECT c.session_id, c.properties, c.creation_time, c.is_open, t.text
FROM sys.dm_exec_cursors (SPID) c --0 for all cursors running
CROSS APPLY sys.dm_exec_sql_text (c.sql_handle) t
Run Code Online (Sandbox Code Playgroud)
结果:
这是一个简单的select. 为什么要使用 f etch_cursor?
另外,我也看到了很多“空白”的 sql_texts。这与这个“光标”有关系吗?
DBCC INPUTBUFFER (spid) 给我看这个:
有这个问题 在这里(我做的),但我不知道这是否是同样的事情。
编辑1:
使用 kin 提供的查询,我看到了这一点:
编辑2:
使用活动监视器,我可以看到:
这是最昂贵的查询(第一个是故意的,我们知道)。
再一次,我想知道,为什么这select * from...是FETCH CURSOR……的原因。
编辑3:
这个“ select * from...”是从另一台服务器(通过linked server)运行的。
好吧,现在我无法理解@kin 所说的内容。
这是execution plan查询的(在数据库的同一服务器中运行):
这是现在,通过链接服务器在另一台服务器上运行的执行计划:
好的,也不是问题。现在!执行计划,通过**activity monitor**(相同select * from):
我们正在使用 SQL Server 2012 运行 Dynamics AX 2012 安装。我知道不应再使用游标,但 AX 正在使用它,我们无法更改此行为,因此我们必须使用它。
今天我发现了一个非常糟糕的查询,读取次数超过 5300 万次,执行时间超过 20 分钟。
我通过我们的监控工具 SentryOne 捕获了这个查询。
declare @p1 int
set @p1=1073773227
declare @p2 int
set @p2=180158805
declare @p5 int
set @p5=16
declare @p6 int
set @p6=1
declare @p7 int
set @p7=2
exec sp_cursorprepexec @p1 output,@p2 output,N'@P1 bigint,@P2 nvarchar(5),@P3 bigint,@P4 nvarchar(8),@P5 bigint,@P6 bigint,@P7 bigint,@P8 bigint,@P9 bigint,@P10 bigint,@P11 bigint,@P12 bigint,@P13 bigint,@P14 bigint,@P15 bigint,@P16 bigint,@P17 bigint,@P18 bigint,@P19 nvarchar(5),@P20 bigint,@P21 bigint,@P22 bigint,@P23 bigint,@P24 bigint',N'SELECT T1.PRODUCT,T1.EXTERNALVENDPARTY,T1.LIFECYCLESTATUS,T1.RECID,T2.ECORESPRODUCT,T2.ECORESDISTINCTPRODUCTVARIANT,T2.SGE,T2.ECORESREFORDERNUM,T2.ORDERNUM,T2.RECID,T3.ECORESREFORDERNUM,T3.NAME1,T3.NAME2,T3.NAME3,T3.RECID,T4.ECORESPRODUCT,T4.EXTERNALITEMID,T4.ECORESDISTINCTPRODUCTVARIANT,T4.RECID,T5.RECID,T5.PERSON,T6.RECID,T6.NAME,T6.INSTANCERELATIONTYPE,T7.RECID,T7.NAME,T7.INSTANCERELATIONTYPE,T8.PARTY,T8.ACCOUNTNUM,T8.RECID,T9.RECID,T9.DISPLAYPRODUCTNUMBER,T9.INSTANCERELATIONTYPE,T10.PRODUCT,T10.CATEGORY,T10.RECID,T11.RECID,T11.CODE,T11.NAME,T11.INSTANCERELATIONTYPE FROM INVENTTABLE T1 CROSS JOIN ECORESPRODUCTORDERNUM …Run Code Online (Sandbox Code Playgroud) performance sql-server cursors sql-server-2012 microsoft-dynamics performance-tuning
我知道我们倾向于不惜一切代价避免在 SQL Server 中使用游标和循环,但是在哪些情况下您绝对需要过程查询,而基于集合的查询不会给您结果?
我了解两者之间的区别,我只是从未遇到过需要使用游标的情况。我想知道是否有这样的情况。
如果一个存储过程(或视图)当前正在长时间运行的游标中使用,而我更改了该存储过程,游标是否会继续使用存储过程的旧实例,直到游标完成?
对于大型数据集,使用 an 进行分页OFFSET是众所周知的,并且不是最好的分页方式。更好的分页方式是使用游标,它只是行上的一个唯一标识符,因此我们知道从最后一个光标位置上次离开的位置继续分页的位置。
当涉及到一个自动递增id值的游标时,实现起来相当容易:
SELECT * FROM users
WHERE id <= %cursor // cursor is the auto incrementing id, ex. 100000
ORDER BY id DESC
LIMIT %limit
Run Code Online (Sandbox Code Playgroud)
我们不确定的是,如果不是自动递增id游标,游标的唯一唯一顺序标识符是表行上的uuid和created_at。
我们当然可以根据 查询uuid得到created_at,然后选择所有的users,<= created_at但问题是如果表中有多个相同created_at时间戳的实例users怎么办?知道如何users根据uuid/created_at游标组合查询表以确保我们获得正确的数据集(就像我们使用自动递增一样id)?再次,只有独特的领域是uuid因为created_at可能是重复的,但他们的组合是每行唯一的。
我有一个 3rd 方应用程序,它使用一个游标来更新我的 SQL Server 2014 表中的行。我无法修改此代码,因此设计了一种方案,将光标指向具有INSTEAD OF UPDATE触发器的视图,我可以在其中拦截并完全控制更新。我很清楚游标是邪恶的,但我不得不使用它们,因为我无法修改源程序。
当UPDATE ... WHERE CURRENT OF语句执行,它执行聚集索引扫描,而不是寻求以定位光标当前所指向的记录。我无法确定优化器在可能进行搜索时为什么要进行扫描。我相信它是导致问题的光标 + 视图 + 而不是更新触发器的组合,因为如果我从我的测试中删除这 3 个变量中的任何一个,索引查找就会被正确使用。
请注意,表中有多少行并不重要;优化器总是根据执行计划使用扫描。我什至删除了触发器中的所有逻辑以进一步简化测试。
下面是一些简单的代码来重现这个问题:
CREATE TABLE [dbo].[Person](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](40) NULL,
CONSTRAINT [PK_Person_Id] PRIMARY KEY CLUSTERED ( [Id] ASC )
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY])
ON [PRIMARY]
GO
CREATE VIEW [dbo].[vPerson]
AS SELECT Id, Name FROM dbo.Person …Run Code Online (Sandbox Code Playgroud) 我想知道游标的一般替换是什么。我看到的游标的一般实现是
DECLARE @variable INT, @sqlstr NVARCHAR(MAX)
DECLARE cursor_name CURSOR
FOR select_statement --essentially to get an array for @variable
--usually it's a subset of unique ids for accounts, clients, parts, etc
OPEN cursor_name
FETCH NEXT FROM cursor_name INTO @variable
WHILE @@FETCH_STATUS = 0
BEGIN
SET @sqlstr = N'
/* some query that uses '+ str(@variable) +' to do dirty work
such as: go through all our accounts, if it''s some subset (possible new cursor),
go through those accounts and connect this …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用游标来清理不再需要的临时表。我有一个小表,其中包含临时表的名称和标识符。游标陷入无限循环,但前提是我在其中执行某些语句。如果我只是打印出 中的值FETCH,它就可以完美运行。这是代码。
DECLARE @id bigint;
DECLARE @table_name varchar(max);
DECLARE st CURSOR LOCAL FAST_FORWARD FOR
SELECT ID, TableName FROM SearchTables WHERE CustomerID IS NULL
OPEN st
FETCH NEXT FROM st INTO @id, @table_name
WHILE @@FETCH_STATUS <> -1
BEGIN
IF(OBJECT_ID(@table_name) IS NOT NULL)
EXEC('DROP TABLE ' + @table_name);
UPDATE SearchTables SET Deleted=1 WHERE ID=@id;
PRINT CAST(@id AS varchar(max)) + ' ' + @table_name;
FETCH NEXT FROM st INTO @id, @table_name;
END
CLOSE st
DEALLOCATE st
Run Code Online (Sandbox Code Playgroud)
如果我注释掉这些行
IF(OBJECT_ID(@table_name) IS NOT NULL) …Run Code Online (Sandbox Code Playgroud) cursors ×10
sql-server ×7
performance ×3
t-sql ×2
ddl ×1
mysql ×1
mysql-5.7 ×1
paging ×1
parallelism ×1
process ×1
select ×1
trigger ×1