简体   繁体   English

SQL Server查询性能降低和优化

[英]SQL Server Query Performance Degradation and Optimization

I've inherited several data sources and I've been tasked with integration and report. 我继承了几个数据源,并负责集成和报告。 Nothing new. 没什么新鲜的。

The issue is that while I have a working integrated query (as a view), performance degrades daily (from 8 to 12 seconds). 问题是,尽管我有一个有效的集成查询(作为视图),但是性能每天都会下降(从8到12秒)。

Here is a slightly simplified version of the table schema and a working query to get the list of tickets. 这是表模式的略微简化版本,以及用于获取故障单列表的有效查询。

/*  Table Schema  */
CREATE TABLE [dbo].[KioskImport](
    [ImportID] [bigint] IDENTITY(1,1) NOT NULL,
    [ImportDate] [datetime] NOT NULL,
    [TICKET_NBR] [varchar](25) NULL,
    [TTL_AMT] [decimal](18, 2) NOT NULL,
    [GROUP_ID] [varchar](15) NULL,
    [SALE_DT] [date] NULL,
    [SALE_TMS] [time](0) NULL,
    [BADGE_NO] [varchar](25) NULL
) ON [PRIMARY]

/*  Working Query  */
SELECT 
    [KioskImport].TICKET_NBR
    ,[KioskImport].GROUP_ID
    ,[KioskImport].TTL_AMT
    ,CONVERT(datetime, [KioskImport].SALE_DT) + CONVERT(datetime, [KioskImport].SALE_TMS) AS [SALE_DATE]
    ,[KioskImport].BADGE_NO
FROM [KioskImport]
INNER JOIN 
(
    SELECT MAX(ImportID) MaxID, MAX(ImportDate) MaxDate, TICKET_NBR
    FROM [KioskImport]
    GROUP BY TICKET_NBR
) [MaxRevenueImport]
ON [MaxRevenueImport].MaxID = [KioskImport].ImportID
AND [MaxRevenueImport].MaxDate = [KioskImport].ImportDate

From here I have a view that joins several queries like this to create a product result set. 在这里,我有一个视图,该视图将这样的几个查询联接在一起以创建产品结果集。

Does anyone have good suggestions on how to optimize this query so as to mitigate the ongoing performance degradation (buying enough time to redesign...everything). 是否有人对如何优化此查询以减轻持续的性能下降(花足够的时间进行重新设计……一切)有很好的建议。

SQL Version is 2008 R2 SQL版本是2008 R2

As some of the other folks pointed out, you should note what version of SQL you are using. 正如其他一些人指出的那样,您应该注意所使用的SQL版本。 That said, this might perform better as a CROSS APPLY . 也就是说,作为CROSS APPLY可能会更好。 Try changing your query to: 尝试将查询更改为:

SELECT 
    [KioskImport].TICKET_NBR
    ,[KioskImport].GROUP_ID
    ,[KioskImport].TTL_AMT
    ,CONVERT(datetime, [KioskImport].SALE_DT) + CONVERT(datetime, [KioskImport].SALE_TMS) AS [SALE_DATE]
    ,[KioskImport].BADGE_NO
FROM [KioskImport] kiOuter
CROSS APPLY (
    SELECT
        kiInner.TICKET_NBR
    FROM [KioskImport] kiInner
    GROUP BY
        kiInner.TICKET_NBR
    HAVING 
        MAX(kiInner.ImportID) = kiOuter.ImportID
        AND MAX(kiInner.ImportDate) = kiOuter.ImportDate
    ) kiInner

Also, if you're seeing query performance change this dramatically over the course of a single day, you likely either are having fragmentation from heavy table churn, are comparing cached vs. uncached query performance, or the server is running other workloads. 另外,如果您看到查询性能在一天的过程中发生了巨大变化,则可能是由于大量表搅动导致碎片化,正在比较缓存的查询性能与未缓存的查询性能,或者服务器正在运行其他工作负载。

I bet 'cross apply' run slower. 我敢打赌“交叉申请”的速度会变慢。 My question for you is when you have MAX(kiInner.ImportID) what is MAX(kiInner.ImportDate) for that ImportID, or when you get MAX(kiInner.ImportDate) what is MAX(kiInner.ImportID) for that ImportDate. 我的问题是,当您拥有该导入ID的MAX(kiInner.ImportDate)是什么时,或者当您获得该ImportDate的MAX(kiInner.ImportDate)是什么MAX(kiInner.ImportID)时。 They maybe not in the same row. 他们可能不在同一行。 I suggest to use CTE. 我建议使用CTE。

;WITH cte AS (SELECT TICKET_NBR
               , ImportID
               , ImportDate
               , ROW_NUMBER() OVER(PARTITION BY TICKET_NBR              
                    ORDER BY ImportDate DESC, ImportID DESC) AS Rownum
          FROM KioskImport
)
SELECT [KioskImport].TICKET_NBR
    ,[KioskImport].GROUP_ID
    ,[KioskImport].TTL_AMT
    ,CONVERT(datetime, [KioskImport].SALE_DT) + CONVERT(datetime,  [KioskImport].SALE_TMS) AS [SALE_DATE]
    ,[KioskImport].BADGE_NO
FROM [KioskImport] k
INNER JOIN cte cte
     ON cte.ImportID = k.ImportID
     AND cte.ImportDate = k.ImportDate
     AND cte.Rownum = 1;

use this before the select : 在select之前使用它:

SELECT MAX(ImportID) MaxID, MAX(ImportDate) MaxDate, TICKET_NBR
into #MaxRevenueImport
    FROM [KioskImport]
    GROUP BY TICKET_NBR

then use #MaxRevenueImport at your join. 然后在您的联接中使用#MaxRevenueImport。 If #MaxRevenueImport has more than 10000 rows create index on the temp at TICKET_NBR before the join in the main select. 如果#MaxRevenueImport具有超过10000行,则在主选择中的联接之前,在TICKET_NBR上的临时位置上创建索引。 Do not use table variable use temp #. 不要使用表变量使用temp#。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM