如何避免使用Sub查询&优化下面提到的查询?

时间:2014-02-28 12:17:19

标签: sql sql-server optimization indexing subquery

    ---------------------------------- Lead MASTER TABLE
Create table leads
(
    pk_lead_id int primary key identity,
    lead_name varchar(50),
    lead_mobile varchar(50)
)


insert into leads
        select 'AK','9876543210'
insert into leads
        select 'AK1','9876543210'
--....
insert into leads
        select 'AK1000','9876543210'

----------------------------------Lead TRANSACTION TABLE

Create table lead_tr
(
    pk_leadtr_id int primary key identity,
    fk_lead_id int,
    tr_date datetime,
    tr_remarks varchar(500)
)

--- For Lead ID 1
insert into lead_tr select 1,GETDATE(),'This is First Transaction'
insert into lead_tr select 1,GETDATE(),'This is Second Transaction'
--...
insert into lead_tr select 1,GETDATE(),'This is Hundredth Transaction'

--- For Lead ID 1000
insert into lead_tr select 2,GETDATE(),'This is First Transaction'
insert into lead_tr select 2,GETDATE(),'This is Second Transaction'
---...
insert into lead_tr select 2,GETDATE(),'This is Hundredth Transaction'

------------------- MY PROC. for Lead Details With Latest STATUS


select * from leads
left join
    (
        select fk_lead_id,max(pk_leadtr_id) as pk_leadtr_id from lead_tr
        group by fk_lead_id
    )as ltmin on ltmin.fk_lead_id = pk_lead_id
left join lead_tr as lt on lt.pk_leadtr_id = ltmin.pk_leadtr_id

我的潜在客户表包含大量记录。 并且事务表将为每行引线包含50个事务。 如何避免子查询?如何优化此SP。 我需要改变我的表结构吗?

4 个答案:

答案 0 :(得分:0)

首先,您应该在fk_lead_id

上为lead_tr添加索引

建议您尝试交叉申请

例如,您可以使用类似于此的内容

select L.*, XL.*
from Leads L
cross apply (
    select max(pk_leadtr_id) as tr_id
           from lead_tr TR
           where TR.fk_lead_id = L.pk_lead_id
    ) XL

Cross Apply几乎总是我体验中最快的方法

网上有很多交叉应用教程,还有外部应用(对应外连接)

答案 1 :(得分:0)

Mathese F,你怎么能使用union all,union all,union all重复“row count”次来插入一些temp ...然后是一些触发器?拜托......

请不要使用他的任何建议。尝试使用窗口函数来选择最近的子行。

;WITH temp 
     AS (SELECT ROW_NUMBER() OVER (PARTITION BY tr.fk_lead_id ORDER BY tr.pk_leadtr_id DESC) AS marker, 
                * 
         FROM   leads AS s 
                LEFT JOIN lead_tr AS tr 
                       ON tr.fk_lead_id = s.pk_lead_id ) 
SELECT * 
FROM   temp 
WHERE  temp.marker = 1 
        OR temp.marker IS NULL 
ORDER  BY pk_lead_id 

详细了解窗口函数here或其他任何地方。

答案 2 :(得分:0)

我同意Gary Walker的APPLY逻辑是最好的方法,但我不同意该申请。我认为您的查询应该是:

SELECT  *
FROM    Leads L
        OUTER APPLY
        (   SELECT  TOP 1 *
            FROM    Lead_tr tr 
            WHERE   tr.fk_lead_id = l.pk_lead_id
            ORDER BY tr.pk_leadtr_id DESC
        ) tr;

<强> Example on SQL Fiddle

这使您可以从Lead_tr获取所有列,而无需再次加入。

您也可以使用ROW_NUMBER()函数执行此操作,这样您的示例中的逻辑读取次数较少,但在测试时使用APPLY时执行速度始终较慢:

SELECT  *
FROM    Leads L
        LEFT JOIN
        (   SELECT  *, RowNum = ROW_NUMBER() OVER(PARTITION BY tr.fk_lead_id ORDER BY tr.pk_leadtr_id DESC)
            FROM    Lead_tr tr
        ) tr
            ON tr.fk_lead_id = l.pk_lead_id
            AND tr.RowNum = 1;

<强> Example on SQL Fiddle


比较性能

应用

  

(3行受影响)

     

表'lead_tr'。扫描计数1,逻辑读取7,物理读取0,预读取读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。

     

表'线索'。扫描计数1,逻辑读取2,物理读取0,预读取读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。

     

SQL Server执行时间:CPU时间= 0毫秒,已用时间= 48毫秒。

<强> ROW_NUMBER

  

(3行受影响)

     

表'lead_tr'。扫描计数1,逻辑读取2,物理读取0,预读取读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。

     

表'线索'。扫描计数1,逻辑读取2,物理读取0,预读取读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。

     

SQL Server执行时间:CPU时间= 0毫秒,已用时间= 146毫秒。

N.B两个查询都在一个热缓存上运行,因此两者的编译时间都是0ms,因此不包含在上面。

在您的实际数据中,您可能会得到不同的结果,因此一如既往地测试您的数据并选择最适合您的方法。

答案 3 :(得分:-1)

我首先建议使用union而不是这个。

例如:

insert into leads
select 'AK','9876543210'
union
select 'AK1','9876543210'
union
select 'AK1000','9876543210'

一个操作而不是一个操作将花费成本。

这些价​​值来自哪里?

然后你可以想象有一个触发器,它将具有创建事务的小好处。即使不在sp中也适用

50是固定的吗?它们是如何创建的?

你能想象在这里的第一个表和另一个表之间进行连接以插入它们吗?

至少你总会有2个插入(可能带有输出子句,它可能很好)

<强>更新

以下是输出示例:

declare @test table (i int)
declare @test2 table (i int, dada date )

insert into @test 
output inserted.*, GETDATE() into @test2
values (1)

select * from @test
select * from @test2

我的执行计划只显示一个查询而不是2,所以我认为如果可能的话会更好。