我的查询在 SSMS 中很快,但在我的应用程序中超过 1 小时

Posted

技术标签:

【中文标题】我的查询在 SSMS 中很快,但在我的应用程序中超过 1 小时【英文标题】:my query is fast in SSMS but goes over 1 hour in my app 【发布时间】:2018-11-07 22:50:46 【问题描述】:

我的应用程序中的查询速度很慢,但在 SSMS 中查询速度非常快。看到一些答案后,我注意到执行计划似乎有所不同。

我注意到,当我使用 SSMS 时,使用了称为 [Parallelism (Repartition Streams)] 的东西,但我在来自 C# 应用程序的执行计划中没有看到它(我在 SSMS 中使用 Activity Monitor 来查看)。此外,当我使用我的应用程序时,我看到查询列在“Active Expensive Queries”列表中,但当我从 SSMS 运行它时,情况并非如此。

我将添加我的查询,但为了我的公司隐私,我会尝试隐藏一些文本:

SELECT  [REC_INVENT_LIST_ID]
      , ril.[NOTE_TYPE_ID]
      , ril.[TRANS_ID] 
      , [QUANTITIES]
      , [AMOUNT]
      , nt.[CU_TYPE]
      , nt.[CASH_TYPE]
      , nt.[NOTE_VALUE]
      , nt.[UNIT_ID]
      , t.RECYCLER_ID
FROM [D].[dbo].[RecyclerInventoryList] ril
JOIN [S].[dbo].[NoteType] nt ON nt.NOTE_TYPE_ID = ril.NOTE_TYPE_ID
JOIN [D].[dbo].[Transaction] t ON ril.TRANS_ID = t.TRANS_ID
WHERE QUANTITIES <> 0
AND ril.TRANS_ID IN (
        SELECT sub.TRANS_ID FROM (SELECT *, MAX(CREATE_DATE) 
        OVER(PARTITION BY t.RECYCLER_ID) AS _max
        FROM [D].[dbo].[Transaction] AS t
        WHERE TRANS_ID <= @lastTransId) AS sub
        WHERE CREATE_DATE = _max
                 )
ORDER BY t.RECYCLER_ID, CU_TYPE 

我所做的是:

1- 我试图删除显示WHERE TRANS_ID &lt;= @lastTransId 的部分,以确保它不是参数转换问题,但这没有帮助。

2- 我删除了上面写着WHERE CREATE_DATE = _max 的部分,我很快就在应用程序中得到了结果!但这不是我想要的结果。这对我来说真的很重要。

3- 我使用 SQL SERVER PROFILER 查看在我的应用程序超时和崩溃(1 小时命令超时)后尝试运行的确切查询是这样的

exec sp_executesql N'SELECT [REC_INVENT_LIST_ID], ril.[NOTE_TYPE_ID], ril.[TRANS_ID], [QUANTITIES], [AMOUNT], nt.[CU_TYPE], nt.[CASH_TYPE], nt.[NOTE_VALUE], nt.[UNIT_ID], t.[RECYCLER_ID] FROM[RCMDYNAMIC].[dbo].[RecyclerInventoryList] ril JOIN[RCMSTATIC].[dbo].[NoteType] nt ON nt.NOTE_TYPE_ID = ril.NOTE_TYPE_ID JOIN[RCMDYNAMIC].[dbo].[Transaction] t ON ril.TRANS_ID = t.TRANS_ID  WHERE QUANTITIES<> 0 AND ril.TRANS_ID IN (SELECT sub.TRANS_ID FROM (SELECT TRANS_ID, CREATE_DATE , MAX(CREATE_DATE) OVER(PARTITION BY t.RECYCLER_ID) AS _max FROM[RCMDYNAMIC].[dbo].[Transaction] AS t WHERE TRANS_ID <= @lastTransId ) AS sub WHERE CREATE_DATE = _max) ORDER BY t.RECYCLER_ID, CU_TYPE',N'@lastTransId int',@lastTransId=XXXXX

当我在 SSMS 上运行它时,它仍然非常快(毫秒),并且执行计划似乎与我直接从 SSMS 运行查询时相同。

有什么想法吗?

编辑:

我的 C# 代码:

public Dictionary<int, List<RCMBalanceTransactionModel>> getBalanceTransactions(int transId) 

        SqlCommand command;
        SqlDataReader reader;
        command = new SqlCommand(getBalanceTransactionInfoQuery(), con);
        command.CommandTimeout = 3600;
        command.Parameters.AddWithValue("@lastTransId", transId);
        reader = command.ExecuteReader();


  //the rest is omitted the application is stuck here at ExecutedReader();

【问题讨论】:

评论不用于扩展讨论;这个对话是moved to chat。 【参考方案1】:

根据您对其他答案的评论,如果您只是想获取每个 recycler_id 的最新 TRANS_ID,您可以使用下面的查询来完成。这假设您的 ID 是按顺序生成的。如果您可以确定来自同一个回收站的两个事务没有相同的 CREATE_DATE,那么您也可以对 CREATE_DATE 执行基本相同的操作。我不确定您的 @lastTransId 目标,因此您可能需要将其添加到 where 子句中。

SELECT  
    [REC_INVENT_LIST_ID]
      , ril.[NOTE_TYPE_ID]
      , ril.[TRANS_ID] 
      , [QUANTITIES]
      , [AMOUNT]
      , nt.[CU_TYPE]
      , nt.[CASH_TYPE]
      , nt.[NOTE_VALUE]
      , nt.[UNIT_ID]
      , t.RECYCLER_ID
FROM 
    [D].[dbo].[RecyclerInventoryList] ril
    JOIN [S].[dbo].[NoteType] nt 
        ON nt.NOTE_TYPE_ID = ril.NOTE_TYPE_ID
    JOIN [D].[dbo].[Transaction] t 
        ON ril.TRANS_ID = t.TRANS_ID
    LEFT OUTER JOIN [D].[dbo].[Transaction] t2
        ON t.RECYCLER_ID = t2.RECYCLER_ID AND t.TRANS_ID < t2.TRANS_ID
WHERE
    t2.TRANS_ID IS NULL AND /* This is null only for t.TRANS_ID that have no records greater than itself, ie the latest one */
    QUANTITIES <> 0
ORDER BY 
    t.RECYCLER_ID, CU_TYPE 

【讨论】:

【参考方案2】:

我试图重写查询,但没有数据我不确定我是否正确

SELECT  [REC_INVENT_LIST_ID]
      , ril.[NOTE_TYPE_ID]
      , ril.[TRANS_ID] 
      , [QUANTITIES]
      , [AMOUNT]
      , nt.[CU_TYPE]
      , nt.[CASH_TYPE]
      , nt.[NOTE_VALUE]
      , nt.[UNIT_ID]
      , t.RECYCLER_ID
FROM [D].[dbo].[RecyclerInventoryList] ril
JOIN [S].[dbo].[NoteType] nt ON nt.NOTE_TYPE_ID = ril.NOTE_TYPE_ID
JOIN [D].[dbo].[Transaction] t ON ril.TRANS_ID = t.TRANS_ID
WHERE QUANTITIES <> 0
AND t.TRANS_ID <= @lastTransId
AND NOT EXISTS(SELECT 1 FROM [D].[dbo].[Transaction] AS t2 
    WHERE t2.RECYCLER_ID = t.RECYCLER_ID 
      AND t2.CREATE_DATE > t.CREATE_DATE 
          AND t2.TRANS_ID <= @lastTransId)

ORDER BY t.RECYCLER_ID, CU_TYPE 

【讨论】:

我明天就可以测试了。我想要对查询执行的操作是获取每个 Recycler 的最新交易,这就是为什么我使用 'OVER(PARTITION BY t.RECYCLER_ID) AS _max' 如果这就是你想要做的,你通常可以用左连接来做到这一点。但是您是否尝试将您的 where sub select 移动到 join sub select? @Neil.Work 将在早上尝试这第一件事我下班了哈哈 @Neil.Work 我在这里看不到优势,但可以肯定的是,您可以做到。 这更快(20 秒),但我想我找到了主要原因。在我的连接字符串中,我将 Initial Catalog 设置为数据库 D,而在此查询中也使用了数据库 S。在我从连接字符串中删除它之后,它是即时的!上面的 cmets 中有人提到了连接字符串部分。如果他把这个作为答案,我想我可以接受。

以上是关于我的查询在 SSMS 中很快,但在我的应用程序中超过 1 小时的主要内容,如果未能解决你的问题,请参考以下文章

过程在 ADO.NET 中超时,但在 SSMS 中没有

在SSMS中超链接SQL Server查询结果中的值

SP 在强大的服务器上很慢,但在本地很快(都来自 SSMS)

ODBC 查询在 MS Access 中有效,但在 SQL Server 中超时

插入查询在 SSMS 中有效,但在 SQLCMD 中无效

如何在我的查询中修复此语法错误?