简体   繁体   English

SQL Server 2012 - 提高查询性能

[英]SQL Server 2012 - Improve query performance

I'm looking for a way to improve the following query. 我正在寻找一种方法来改进以下查询。

It collects members of organizations that have a membership of any organization in 2013. 它收集2013年拥有任何组织成员的组织的成员。

I've been able to determine that the sub-query in this query is the real performance killer, but I can't find a way to remove the subquery and keep the resulting table correct. 我已经能够确定此查询中的子查询是真正的性能杀手,但我找不到删除子查询并保持结果表正确的方法。

The query simply collects all "PersonID" and "MemberId" for people that have a membership in this calendar year. 该查询仅为在此日历年具有成员资格的人收集所有“PersonID”和“MemberId”。 BUT, it is possible to have two memberships in one calendar year. 但是,可以在一个日历年内拥有两个会员资格。 If that should happen, then we only want to select the last membership you have in that calendar year: that's what the subquery is for. 如果发生这种情况,那么我们只想选择该日历年中您拥有的最后一个成员资格:这就是子查询的用途。

A "WorkingYear" is not the same as a calendar year. “WorkingYear”与日历年不同。 A workingyear can be an entire year, but it can also run from september 2013 to september 2014, for example. 工作年限可以是一整年,但也可以从2013年9月到2014年9月。 That's why I specify that the workingyear has to start or end in 2013. 这就是为什么我指定工作年必须在2013年开始或结束。

This is the query: 这是查询:

SELECT DISTINCT PersonID,
                m.id AS MemberId
FROM   Members AS m
       INNER JOIN WorkingYears AS w
         ON m.WorkingYearID = w.ID
            AND ( YEAR(w.StartDate) = 2013
                   OR YEAR(w.EndDate) = 2013 )
WHERE  m.Id = (SELECT TOP 1 m2.id
               FROM   DBA_Member m2
               WHERE  personid = m.PersonID
                      AND ( ( droppedOut = 'false' )
                             OR ( droppedOut = 'true'
                                  AND ( yeardropout = 2013 ) ) )
               ORDER  BY m.StartDate DESC) 

This query should collect about 50.000 rows for me, so obviously it also executes the sub query at least 50.000 times and I'm looking for a way to avoid this. 这个查询应该为我收集大约50.000行,所以显然它也执行子查询至少50.000次,我正在寻找一种方法来避免这种情况。 Does anyone have any ideas that could point me in the right direction? 有没有人有任何想法可以指出我正确的方向?

All fields that are used in JOINS should be indexed correctly. 应正确索引JOINS中使用的所有字段。 There is also a seperate index on 'droppedOut' (bit), 'yeardropout' (int). 'lostOut'(位),'yeardropout'(int)上还有一个单独的索引。 I also created an index on both fields at the same time to no avail. 我也同时在两个字段上创建了一个索引但无济于事。

In the execution plan, I see that an "eager spool" is occurring, that takes up 60% of the query time. 在执行计划中,我看到正在发生“急切的假脱机”,占用查询时间的60%。 It has an outputlist of Member.ID, Member.DroppedOut, Member.YearDropout, which are indeed all the fields that I'm using in my subquery. 它有一个Member.ID,Member.DroppedOut,Member.YearDropout的输出列表,它确实是我在子查询中使用的所有字段。 Also, it gets 50.500 rebinds. 此外,它获得了50.500个篮板。

Does anyone have any advice? 有人有建议吗?

You only need to do the sub-query once if you use a CTE 如果使用CTE,则只需执行一次子查询

WITH subQall AS
(
  select id, personID, 
             ROW_NUMBER() OVER (PARTITION BY personID ORDER BY StartDate DESC) as rnum
  from DBA_Member 
  WHERE (droppedOut='false') OR (droppedOut='true' AND (yeardropout = 2013))
), subQ AS
(
  select id, personID
  from subQall
  where rnum = 1
)
SELECT DISTINCT PersonID, m.id as MemberId
FROM Members AS m
INNER JOIN WorkingYears AS w ON m.WorkingYearID = w.ID
JOIN subQ ON m.ID = subQ.ID and m.personID = subQ.personID
WHERE StartDate BETWEEN '1-1-2013' AND '12-31-2013'

Can you try a join instead of the sub query? 你可以尝试连接而不是子查询吗?

like this 像这样

SELECT DISTINCT PersonID, m.id as MemberId
FROM Members AS m

INNER JOIN WorkingYears AS w ON m.WorkingYearID = w.ID
AND (year(w.StartDate) = 2013 OR year(w.EndDate) = 2013)

JOIN (select top 1 m2.id ID from DBA_Member m2 where personid= m.PersonID
       and ((droppedOut='false') OR (droppedOut='true' AND (yeardropout = 2013)))
       order by m.StartDate desc) Member ON m.Id = Member.ID

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

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