首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Sql查询穿透行优化

Sql查询穿透行优化
EN

Stack Overflow用户
提问于 2010-08-06 22:19:17
回答 2查看 386关注 0票数 2

下面是我的表结构

代码语言:javascript
复制
MyTable
-----------

ObjectID int (Identity),           -- Primary Key
FileName varchar(10),
CreatedDate datetime
...........
...........
...........

我需要获取在文件中创建记录所用的时间...即..。同一文件中的前一条记录与同一文件的当前记录之间经过的时间

即..。如果记录是

代码语言:javascript
复制
ObjectID    FileName    CreatedDate (just showing the time part here)
--------    --------    -----------
1           ABC         10:23
2           ABC         10:25
3           DEF         10:26
4           ABC         10:30
5           DEF         10:31
6           DEF         10:35

所需的输出为...

代码语言:javascript
复制
ObjectID    FileName    CreatedDate     PrevRowCreatedDate
--------    --------    ----------- ---------------
1           ABC         10:23           NULL
2           ABC         10:25           10:23
3           DEF         10:26           NULL
4           ABC         10:30           10:25
5           DEF         10:31           10:26
6           DEF         10:35           10:31

到目前为止,我收到了这个查询,但它花费的时间比预期的要长……有没有更好的方法...

代码语言:javascript
复制
    Select  A.ObjectID, 
        A.FileName
        A.CreatedDate as CreatedDate, 
        B.PrevRowCreatedDate,
        datediff("SS", '1900-01-01 00:00:00', Coalesce((A.CreatedDate - B.PrevRowCreatedDate),0)) as secondsTaken
    from MyTable as A 
        Cross Apply (       
        (Select PrevRowCreatedDate = Max(CreatedDate) from MyTable as BB 
                        where   BB.FileName = A.FileName and 
                                BB.CreatedDate < A.CreatedDate
        )
        ) as B  

如果你需要更多信息,请让我知道

谢谢

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2010-08-06 22:28:01

代码语言:javascript
复制
SELECT t1.FileName, t1.CreatedDate, t2.CreatedDate as PrevCreatedDate
FROM 
   (SELECT FileName, CreateDate,
          ROW_NUMBER() OVER(PARTITION BY FileName ORDER BY CreatedDate) AS OrderNo
   FROM MyTable) t1
LEFT JOIN
   (SELECT FileName, CreateDate,
     ROW_NUMBER() OVER(PARTITION BY FileName ORDER BY CreatedDate) AS OrderNo
     FROM MyTable) t2
ON (t1.FileName = t2.FileName AND t1.OrderNo = t2.OrderNo - 1)

或者更好地使用'WITH',因为查询是相同的:

代码语言:javascript
复制
WITH t(ObjectID, FileName, CreatedDate, OrderNo) AS
   (SELECT ObjectID, FileName, CreatedDate,
          ROW_NUMBER() OVER(PARTITION BY FileName ORDER BY CreatedDate) AS OrderNo
   FROM MyTable) 
SELECT t1.ObjectID, t1.FileName, t1.CreatedDate, t2.CreatedDate AS PrevCreatedDate,
        DATEDIFF("SS", '1900-01-01 00:00:00', 
           COALESCE((t1.CreatedDate - t2.CreatedDate),0)) AS secondsTaken
FROM t t1 LEFT JOIN t t2 
ON (t1.FileName = t2.FileName AND t1.OrderNo = t2.OrderNo + 1)
票数 3
EN

Stack Overflow用户

发布于 2010-08-07 01:50:26

我认为Michael的答案确实应该被证明更有效率。但是,在评估效率时,我只想引起人们注意Management Studio中显示的查询成本(相对于批处理)的一个问题。

我建立了一个有23,174行的测试表,并运行了问题中的查询和Michael的查询。查看实际执行计划中的“查询成本(相对于批处理)”,原始查询是1%,Michael的99%的成本,因此看起来效率非常低。

然而,实际的统计数据告诉我们一个完全不同的故事。

交叉应用方法

SQL Server执行时间: CPU时间=0毫秒,运行时间=0毫秒。

表'MyTable‘。扫描计数23175、逻辑读取49335、物理读取0、预读0、lob逻辑读取0、lob物理读取0、lob预读读取0。

ROW_NUMBER方法

CPU执行时间:

时间=391ms,运行时间=417ms。

表'Worktable‘。扫描计数为0、逻辑读取为0、物理读取为0、预读为0、lob逻辑读取为0、lob物理读取为0、lob预读为0。

表'MyTable‘。扫描计数2、逻辑读取148、物理读取0、预读读取0、lob逻辑读取0、lob物理读取0、lob预读读取0。

ROW_NUMBER计划中,rownumber=rownumber+1上的合并连接两边都有23,174行。这个值是唯一的,实际输出的行数也是23,174。但是,SQL Server估计该连接产生的行数将为34,812,000,因此它对计划中稍后插入操作的估计成本是非常不准确的。

测试脚本

代码语言:javascript
复制
BEGIN TRAN

CREATE TABLE MyTable
  (
     [ObjectID]    [INT] IDENTITY(1, 1) NOT NULL PRIMARY KEY CLUSTERED,
     [FileName]    [VARCHAR](50) NULL,
     [CreatedDate] [DATETIME] NULL
  )

GO

INSERT INTO MyTable
SELECT ISNULL(type, NEWID()),
       DATEADD(DAY, CAST(RAND(CAST(NEWID() AS VARBINARY)) * 10000 AS INT), GETDATE())
FROM   master.dbo.spt_values,
       (SELECT TOP 10 1 AS X FROM  master.dbo.spt_values) V


DELETE FROM MyTable
WHERE  EXISTS(SELECT *
              FROM   MyTable m2
              WHERE  MyTable.CreatedDate = m2.CreatedDate
                     AND MyTable.FileName = m2.FileName
                     AND MyTable.ObjectID < m2.ObjectID)

CREATE UNIQUE NONCLUSTERED INDEX [IX_MyTable]
  ON MyTable ([FileName] ASC, [CreatedDate] ASC)

SET STATISTICS IO ON
SET STATISTICS TIME ON

SELECT A.ObjectID,
       A.FileName,
       A.CreatedDate                                                                                AS CreatedDate,
       B.PrevRowCreatedDate,
       DATEDIFF("SS", '1900-01-01 00:00:00', COALESCE(( A.CreatedDate - B.PrevRowCreatedDate ), 0)) AS secondsTaken
INTO   #A
FROM   MyTable AS A
       CROSS APPLY ((SELECT PrevRowCreatedDate = MAX(CreatedDate)
                     FROM   MyTable AS BB
                     WHERE  BB.FileName = A.FileName
                            AND BB.CreatedDate < A.CreatedDate)) AS B;

WITH t(ObjectID, FileName, CreatedDate, OrderNo)
     AS (SELECT ObjectID,
                FileName,
                CreatedDate,
                RANK() OVER(PARTITION BY FileName ORDER BY CreatedDate) AS OrderNo
         FROM   MyTable)
SELECT t1.ObjectID,
       t1.FileName,
       t1.CreatedDate,
       t2.CreatedDate                                                                          AS PrevCreatedDate,
       DATEDIFF("SS", '1900-01-01 00:00:00', COALESCE(( t1.CreatedDate - t2.CreatedDate ), 0)) AS secondsTaken
INTO   #B
FROM   t t1
       LEFT JOIN t t2
         ON ( t1.FileName = t2.FileName
              AND t1.OrderNo = t2.OrderNo + 1 )

/*Test the 2 queries give the same result*/
SELECT *
FROM   #A
EXCEPT
SELECT *
FROM   #B

SELECT *
FROM   #B
EXCEPT
SELECT *
FROM   #A

ROLLBACK 
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3424650

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档