【问题标题】:Stored Procedure "spins" when executed from Visual Studio 2012从 Visual Studio 2012 执行时存储过程“旋转”
【发布时间】:2021-05-27 04:39:26
【问题描述】:

我已经编写了 3 个存储过程,并且在 SQL Server 中执行时都运行良好。但是,当我在 Visual Studio 2012 中执行它们时,它们只是“旋转”、创建锁等。有什么想法吗?

这是其中之一。另一种是从基于相同 SQL 的内联视图中选择值,而不是插入到 #temp

    @StartDate      As DateTime,
    @EndDate        As DateTime,
    @EmployeeCode   As VarChar(50) = NULL 
AS
BEGIN

SET NOCOUNT ON;


select * into #temp
from 
(SELECT e.Code AS EMPLOYEE_ID,
   e.FirstName AS FIRST_NAME,
   e.LastName AS LAST_NAME,
   ec1.TransactionDate AS DATE_OF_SHIFT,
   ou.Code AS DEPT_UNIT_CODE,
   CASE
       WHEN ec1.Classification = '1' THEN
           MIN(ec1.TransactionDate)
   END AS CLOCK_IN,
   CASE
       WHEN ec2.Classification = '2' THEN
           MAX(ec2.TransactionDate)
   END AS CLOCK_OUT,
   pc.code,
   epb.hourvalue 
FROM APIHealthcare_History_Live.dbo.Employee e (nolock)
JOIN APIHealthcare_Live.dbo.EmployeeClocking ec1 (nolock)
    ON ec1.EmployeeID = e.ID
JOIN APIHealthcare_Live.dbo.EmployeeClocking ec2 (nolock)
    ON ec1.OutClockingGuid = ec2.Guid
JOIN APIHealthcare_Live.dbo.OrganizationUnit ou (nolock)
    ON ec1.OrganizationUnitID = ou.ID
LEFT JOIN APIHealthcare_Live.dbo.EmployeePremiumBucket epb (nolock)
    ON ec1.Guid = epb.TransactionGuid
JOIN APIHealthcare_Live.dbo.PayCode pc (nolock)
    ON epb.PayCodeID = pc.ID
JOIN APIHealthcare_Live.dbo.PayGroupInstance pgi (nolock)
    ON pgi.ID = epb.PayGroupInstanceID
WHERE 

ec1.transactiondate between @StartDate and @EndDate
and epb.PaymentClassification = '1'
AND e.code = @EmployeeCode   

    AND e.ArchiveTaskID =
(
    SELECT MAX(e2.ArchiveTaskID)
    FROM APIHealthcare_History_Live.dbo.Employee e2 (NOLOCK)
    WHERE e2.ID = e.ID
)
GROUP BY e.Code,
     e.FirstName,
     e.LastName,
     ec1.TransactionDate,
     ou.Code,
     ec1.Classification,
     ec2.Classification,
     pc.code,
     epb.hourvalue

UNION
SELECT e.Code AS EMPLOYEE_ID,
   e.FirstName AS FIRST_NAME,
   e.LastName AS LAST_NAME,
   ec1.TransactionDate AS DATE_OF_SHIFT,
   ou.Code AS DEPT_UNIT_CODE,
   CASE
       WHEN ec1.Classification = '1' THEN
           MIN(ec1.TransactionDate)
   END AS CLOCK_IN,
   CASE
       WHEN ec2.Classification = '2' THEN
           MAX(ec2.TransactionDate)
   END AS CLOCK_OUT,
   pc.code,
   epb.hourvalue 
FROM APIHealthcare_History_Live.dbo.Employee e (nolock)
JOIN APIHealthcare_History_Live.dbo.EmployeeClocking ec1 (nolock)
    ON ec1.EmployeeID = e.ID
JOIN APIHealthcare_History_Live.dbo.EmployeeClocking ec2 (nolock)
    ON ec1.OutClockingGuid = ec2.Guid
JOIN APIHealthcare_History_Live.dbo.OrganizationUnit ou (nolock)
    ON ec1.OrganizationUnitID = ou.ID
LEFT JOIN APIHealthcare_History_Live.dbo.EmployeePremiumBucket epb (nolock)
    ON ec1.Guid = epb.TransactionGuid
JOIN APIHealthcare_History_Live.dbo.PayCode pc (nolock)
    ON epb.PayCodeID = pc.ID
JOIN APIHealthcare_History_Live.dbo.PayGroupInstance pgi (nolock)
    ON pgi.ID = epb.PayGroupInstanceID
WHERE 
ec1.transactiondate between @StartDate and @EndDate
and epb.PaymentClassification = '1'
AND e.code = @EmployeeCode     
AND e.ArchiveTaskID =
(
    SELECT MAX(e2.ArchiveTaskID)
    FROM APIHealthcare_History_Live.dbo.Employee e2 (NOLOCK)
    WHERE e2.ID = e.ID
)
AND ou.ArchiveTaskID =
(
    SELECT MAX(ou2.ArchiveTaskID)
    FROM APIHealthcare_History_Live.dbo.OrganizationUnit ou2 (NOLOCK)
    WHERE ou2.ID = ou.ID
)
AND pc.ArchiveTaskID =
(
    SELECT MAX(pc2.ArchiveTaskID)
    FROM APIHealthcare_History_Live.dbo.PayCode pc2 (NOLOCK)
    WHERE pc2.ID = pc.ID
)
                             
GROUP BY e.Code,
     e.FirstName,
     e.LastName,
     ec1.TransactionDate,
     ou.Code,
     ec1.Classification,
     ec2.Classification,
     pc.code,
     epb.hourvalue) as X

select EMPLOYEE_ID, 
FIRST_NAME, 
LAST_NAME,
DATE_OF_SHIFT, 
DEPT_UNIT_CODE,
CLOCK_IN, 
CLOCK_OUT, 
code, 
sum(hourvalue) as Hours
from #temp
group by EMPLOYEE_ID,
FIRST_NAME,
LAST_NAME,
DATE_OF_SHIFT,
DEPT_UNIT_CODE,
CLOCK_IN,
CLOCK_OUT,
CODE
Order by CLOCK_OUT
END


这是另一个。

    @StartDate      As DateTime,
    @EndDate        As DateTime,
    @EmployeeCode   As VarChar(50) = NULL 
AS
BEGIN

SET NOCOUNT ON;


select EMPLOYEE_ID, 
FIRST_NAME, 
LAST_NAME,
DATE_OF_SHIFT, 
DEPT_UNIT_CODE,
CLOCK_IN, 
CLOCK_OUT, 
code, 
sum(hourvalue) as Hours
from 
(
SELECT e.Code AS EMPLOYEE_ID,
   e.FirstName AS FIRST_NAME,
   e.LastName AS LAST_NAME,
   ec1.TransactionDate AS DATE_OF_SHIFT,
   ou.Code AS DEPT_UNIT_CODE,
   CASE
       WHEN ec1.Classification = '1' THEN
           MIN(ec1.TransactionDate)
   END AS CLOCK_IN,
   CASE
       WHEN ec2.Classification = '2' THEN
           MAX(ec2.TransactionDate)
   END AS CLOCK_OUT,
   pc.code,
   epb.hourvalue 
FROM APIHealthcare_History_Live.dbo.Employee e
JOIN APIHealthcare_Live.dbo.EmployeeClocking ec1
    ON ec1.EmployeeID = e.ID
JOIN APIHealthcare_Live.dbo.EmployeeClocking ec2
    ON ec1.OutClockingGuid = ec2.Guid
JOIN APIHealthcare_Live.dbo.OrganizationUnit ou
    ON ec1.OrganizationUnitID = ou.ID
LEFT JOIN APIHealthcare_Live.dbo.EmployeePremiumBucket epb
    ON ec1.Guid = epb.TransactionGuid
JOIN APIHealthcare_Live.dbo.PayCode pc
    ON epb.PayCodeID = pc.ID
JOIN APIHealthcare_Live.dbo.PayGroupInstance pgi
    ON pgi.ID = epb.PayGroupInstanceID
WHERE ec1.transactiondate between @StartDate and @EndDate 
and epb.PaymentClassification = '1'
AND e.code = @EmployeeCode
AND e.ArchiveTaskID =
(
    SELECT MAX(e2.ArchiveTaskID)
    FROM APIHealthcare_History_Live.dbo.Employee e2 (NOLOCK)
    WHERE e2.ID = e.ID
)
GROUP BY e.Code,
     e.FirstName,
     e.LastName,
     ec1.TransactionDate,
     ou.Code,
     ec1.Classification,
     ec2.Classification,
     pc.code,
     epb.hourvalue

UNION
SELECT e.Code AS EMPLOYEE_ID,
   e.FirstName AS FIRST_NAME,
   e.LastName AS LAST_NAME,
   ec1.TransactionDate AS DATE_OF_SHIFT,
   ou.Code AS DEPT_UNIT_CODE,
   CASE
       WHEN ec1.Classification = '1' THEN
           MIN(ec1.TransactionDate)
   END AS CLOCK_IN,
   CASE
       WHEN ec2.Classification = '2' THEN
           MAX(ec2.TransactionDate)
   END AS CLOCK_OUT,
   pc.code,
   epb.hourvalue 
FROM APIHealthcare_History_Live.dbo.Employee e
JOIN APIHealthcare_History_Live.dbo.EmployeeClocking ec1
    ON ec1.EmployeeID = e.ID
JOIN APIHealthcare_History_Live.dbo.EmployeeClocking ec2
    ON ec1.OutClockingGuid = ec2.Guid
JOIN APIHealthcare_History_Live.dbo.OrganizationUnit ou
    ON ec1.OrganizationUnitID = ou.ID
LEFT JOIN APIHealthcare_History_Live.dbo.EmployeePremiumBucket epb
    ON ec1.Guid = epb.TransactionGuid
JOIN APIHealthcare_History_Live.dbo.PayCode pc
    ON epb.PayCodeID = pc.ID
JOIN APIHealthcare_History_Live.dbo.PayGroupInstance pgi
    ON pgi.ID = epb.PayGroupInstanceID
WHERE ec1.transactiondate between @StartDate and @EndDate
and epb.PaymentClassification = '1'
AND e.code = @EmployeeCode
AND e.ArchiveTaskID =
(
    SELECT MAX(e2.ArchiveTaskID)
    FROM APIHealthcare_History_Live.dbo.Employee e2 (NOLOCK)
    WHERE e2.ID = e.ID
)
AND ou.ArchiveTaskID =
(
    SELECT MAX(ou2.ArchiveTaskID)
    FROM APIHealthcare_History_Live.dbo.OrganizationUnit ou2 (NOLOCK)
    WHERE ou2.ID = ou.ID
)
AND pc.ArchiveTaskID =
(
    SELECT MAX(pc2.ArchiveTaskID)
    FROM APIHealthcare_History_Live.dbo.PayCode pc2 (NOLOCK)
    WHERE pc2.ID = pc.ID
)
GROUP BY e.Code,
     e.FirstName,
     e.LastName,
     ec1.TransactionDate,
     ou.Code,
     ec1.Classification,
     ec2.Classification,
     pc.code,
     epb.hourvalue) as X
     
group by
EMPLOYEE_ID, 
FIRST_NAME, 
LAST_NAME,
DATE_OF_SHIFT, 
DEPT_UNIT_CODE,
CLOCK_IN, 
CLOCK_OUT, 
code 
order by date_of_shift, code 
END

【问题讨论】:

  • 有一些“影响计划的选项”会改变 SQL Query Planner 创建计划以执行查询的方式,这些可能会导致执行完全相同的 SQL 代码的不同客户端之间的主要性能差异。比较 ANSI_NULLS、ANSI_PADDING、ANSI_WARNINGS、ARITHABORT、CONCAT_NULL_YIELDS_NULL 和 QUOTED_IDENTIFIER 的 SSMS 和 Visual Studio 设置。通读 Erland Sommarskog 的优秀文章 Slow in the Application, Fast in SSMS? Understanding Performance Mysteries 了解为什么会发生这种情况。
  • 一个非常基本的存储过程SELECT 1 会导致同样的问题吗?我建议您逐步添加代码,直到找到导致问题的部分。或使用sp_whoisactive 确定导致问题的等待类型。

标签: sql-server visual-studio stored-procedures


【解决方案1】:

它们是不同的执行环境。是的,阅读已经推荐的 Sommarskog 的文章。但我认为这些程序缓慢(并且不一致)的主要原因是UNION 运算符。你应该使用UNION ALL。 其次,摆脱这些(nolock)提示。他们不帮助你。如果你真的需要它,你应该使用

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

在您的程序开始时。也一样。

【讨论】:

  • 谢谢先生!我会试一试并发布结果。
猜你喜欢
  • 2013-05-11
  • 1970-01-01
  • 2019-04-03
  • 1970-01-01
  • 2018-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多