SQL request very slow althought index is created

时间:2016-03-02 10:48:28

标签: sql sql-server performance

I have a strange problem with some inner joins on my SQL - Server. It is very slow although all columns that are used in the inner joins and in the where clause have indexes.

Here is my SQL request:

SELECT p.VORNA AS firstName,
       p.NACHN AS lastName,
       p.USRID AS [user],
       o.ORGEH AS OUID,
       o.STEXT AS OU,
       a.HolidayDate AS absentFrom,
       a.HolidayDate AS absentUntil,
       k.MessageDate AS actionDate,
       'holiday' AS reason
FROM Kondor_User_Activities AS k
INNER JOIN dbo.SAP_Personaldaten AS p ON p.USRID = k.Code
INNER JOIN Kondor_Users u ON u.Users_Id = k.Users_Id
INNER JOIN SAP_OE AS o ON p.ORGEH = o.ORGEH
INNER JOIN Kondor_UsersGrp AS g ON g.UsersGrp_Id = u.UsersGrp_Id
INNER JOIN Kondor_Cities AS c ON c.Cities_Id = u.Cities_Id OR (u.Cities_Id IS NULL AND c.Cities_Id = g.Cities_Id)
INNER JOIN Kondor_FixedHolidays AS a ON k.MessageDate >= a.HolidayDate
    AND k.MessageDate < a.HolidayDateEnd
    AND a.Cities_Id = c.Cities_Id
--WHERE g.UsersGrp_ShortName NOT LIKE 'UA_%'
WHERE (g.UsersGrp_ShortName < 'UA_' OR g.UsersGrp_ShortName >= 'UA`')

And here is my execution plan:

  |--Compute Scalar(DEFINE:([Expr1018]='holiday'))
   |--Nested Loops(Inner Join, WHERE:([RevisionReport].[dbo].[Kondor_FixedHolidays].[Cities_Id] as [a].[Cities_Id]=[RevisionReport].[dbo].[Kondor_Cities].[Cities_Id] as [c].[Cities_Id] AND [RevisionReport].[dbo].[Kondor_User_Activities].[MessageDate] as [k].[MessageDate]>=[RevisionReport].[dbo].[Kondor_FixedHolidays].[HolidayDate] as [a].[HolidayDate] AND [RevisionReport].[dbo].[Kondor_User_Activities].[MessageDate] as [k].[MessageDate]<[RevisionReport].[dbo].[Kondor_FixedHolidays].[HolidayDateEnd] as [a].[HolidayDateEnd]))
        |--Parallelism(Gather Streams)
        |    |--Hash Match(Inner Join, HASH:([o].[ORGEH])=([p].[ORGEH]), RESIDUAL:([RevisionReport].[dbo].[SAP_Personaldaten].[ORGEH] as [p].[ORGEH]=[RevisionReport].[dbo].[SAP_OE].[ORGEH] as [o].[ORGEH]))
        |         |--Bitmap(HASH:([o].[ORGEH]), DEFINE:([Bitmap1025]))
        |         |    |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([o].[ORGEH]))
        |         |         |--Table Scan(OBJECT:([RevisionReport].[dbo].[SAP_OE] AS [o]))
        |         |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([p].[ORGEH]), WHERE:(PROBE([Bitmap1025])=TRUE))
        |              |--Hash Match(Inner Join, HASH:([Expr1019])=([p].[USRID]), RESIDUAL:([RevisionReport].[dbo].[SAP_Personaldaten].[USRID] as [p].[USRID]=[Expr1019]))
        |                   |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([Expr1019]))
        |                   |    |--Compute Scalar(DEFINE:([Expr1019]=CONVERT_IMPLICIT(nvarchar(25),[RevisionReport].[dbo].[Kondor_User_Activities].[Code] as [k].[Code],0)))
        |                   |         |--Nested Loops(Inner Join, OUTER REFERENCES:([Bmk1000], [Expr1024]) WITH UNORDERED PREFETCH)
        |                   |              |--Nested Loops(Inner Join, OUTER REFERENCES:([u].[Users_Id]) OPTIMIZED)
        |                   |              |    |--Nested Loops(Inner Join, WHERE:([RevisionReport].[dbo].[Kondor_Cities].[Cities_Id] as [c].[Cities_Id]=[RevisionReport].[dbo].[Kondor_Users].[Cities_Id] as [u].[Cities_Id] OR [RevisionReport].[dbo].[Kondor_Users].[Cities_Id] as [u].[Cities_Id] IS NULL AND [RevisionReport].[dbo].[Kondor_Cities].[Cities_Id] as [c].[Cities_Id]=[RevisionReport].[dbo].[Kondor_UsersGrp].[Cities_Id] as [g].[Cities_Id]))
        |                   |              |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([u].[UsersGrp_Id]))
        |                   |              |    |    |    |--Clustered Index Scan(OBJECT:([RevisionReport].[dbo].[Kondor_Users].[PK_Kondor_Users] AS [u]), ORDERED FORWARD)
        |                   |              |    |    |    |--Clustered Index Seek(OBJECT:([RevisionReport].[dbo].[Kondor_UsersGrp].[PK_Kondor_UsersGrp] AS [g]), SEEK:([g].[UsersGrp_Id]=[RevisionReport].[dbo].[Kondor_Users].[UsersGrp_Id] as [u].[UsersGrp_Id]),  WHERE:([RevisionReport].[dbo].[Kondor_UsersGrp].[UsersGrp_ShortName] as [g].[UsersGrp_ShortName]<'UA_' OR [RevisionReport].[dbo].[Kondor_UsersGrp].[UsersGrp_ShortName] as [g].[UsersGrp_ShortName]>='UA`') ORDERED FORWARD)
        |                   |              |    |    |--Table Spool
        |                   |              |    |         |--Index Scan(OBJECT:([RevisionReport].[dbo].[Kondor_Cities].[IX_Kondor_Cities_Countries_Id] AS [c]))
        |                   |              |    |--Index Seek(OBJECT:([RevisionReport].[dbo].[Kondor_User_Activities].[IX_Kondor_User_Activities_Users_Id] AS [k]), SEEK:([k].[Users_Id]=[RevisionReport].[dbo].[Kondor_Users].[Users_Id] as [u].[Users_Id]) ORDERED FORWARD)
        |                   |              |--RID Lookup(OBJECT:([RevisionReport].[dbo].[Kondor_User_Activities] AS [k]), SEEK:([Bmk1000]=[Bmk1000]) LOOKUP ORDERED FORWARD)
        |                   |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([p].[USRID]))
        |                        |--Table Scan(OBJECT:([RevisionReport].[dbo].[SAP_Personaldaten] AS [p]))
        |--Table Scan(OBJECT:([RevisionReport].[dbo].[Kondor_FixedHolidays] AS [a]))

It got better with the indexes but it is still very very slow when fetching all the data. Maybe, someone has some hints for me how to get all the rows in a reasonable time.

Thank you very much!

Table sizes:

Kondor_FixedHolidays:         14,416 rows
SAP_Personaldaten:            13,001 rows
Kondor_User_Activities:    7,247,086 rows

Here is my execution plan, too, and I think the error is at Kondor_Users_Activities table although I have two indexes there. Maybe, a clustered index would do good there instead of an non-clustered index?

Query Plan

RID Lookup Properties

4 个答案:

答案 0 :(得分:0)

试试这个 -

CREATE NONCLUSTERED INDEX ix1
ON dbo.Kondor_User_Activities (Code, Users_Id, MessageDate)
GO

SELECT  p.VORNA AS firstName, 
        p.NACHN AS lastName, 
        p.USRID AS [USER], 
        o.ORGEH AS OUID, 
        o.STEXT AS OU, 
        a.HolidayDate AS absentFrom, 
        a.HolidayDateEnd AS absentUntil, 
        k.MessageDate AS actionDate,
        'holiday' as reason
FROM dbo.Kondor_User_Activities k 
JOIN dbo.SAP_Personaldaten p ON p.USRID = k.Code
JOIN dbo.SAP_OE o ON p.ORGEH = o.ORGEH 
JOIN dbo.Kondor_Users u ON u.Users_Id = k.Users_Id 
JOIN dbo.Kondor_UsersGrp g ON g.UsersGrp_Id = u.UsersGrp_Id
JOIN dbo.Kondor_FixedHolidays a ON k.MessageDate >= a.HolidayDate AND k.MessageDate < a.HolidayDateEnd AND a.Cities_Id = g.Cities_Id
WHERE (g.UsersGrp_ShortName < 'UA_' OR g.UsersGrp_ShortName >= 'UA`')
    AND EXISTS(
        SELECT 1
        FROM Kondor_Cities c
        WHERE c.Cities_Id IN (u.Cities_Id, g.Cities_Id)
        --WHERE c.Cities_Id = ISNULL(u.Cities_Id, g.Cities_Id)
    )

答案 1 :(得分:0)

我怀疑大部分减速来自此加入INNER JOIN Kondor_Cities AS c ON c.Cities_Id = u.Cities_Id OR (u.Cities_Id IS NULL AND c.Cities_Id = g.Cities_Id)。 SqlServer不擅长优化OR谓词。

请改为尝试:

SELECT  p.VORNA AS firstName, 
        p.NACHN AS lastName, 
        p.USRID AS [USER], 
        o.ORGEH AS OUID, 
        o.STEXT AS OU, 
        x.HolidayDate AS absentFrom, 
        x.HolidayDate AS absentUntil, 
        k.MessageDate AS actionDate,
        'holiday' as reason
FROM        Kondor_User_Activities AS k 
      INNER JOIN dbo.SAP_Personaldaten AS p ON p.USRID = k.Code
        INNER JOIN Kondor_Users u ON u.Users_Id = k.Users_Id 
          INNER JOIN SAP_OE AS o ON p.ORGEH = o.ORGEH 
            INNER JOIN Kondor_UsersGrp AS g ON g.UsersGrp_Id = u.UsersGrp_Id
              INNER JOIN (
                    SELECT DISTINCT a.HolidayDate, a.HolidayDateEnd, a.Cities_Id
                    FROM Kondor_FixedHolidays AS a
              ) x ON k.MessageDate >= x.HolidayDate and k.MessageDate < x.HolidayDateEnd AND x.Cities_Id IN (u.Cities_Id,g.Cities_Id)
WHERE (g.UsersGrp_ShortName < 'UA_' OR g.UsersGrp_ShortName >= 'UA`')

答案 2 :(得分:0)

加入不喜欢OR
你可以用isnull去除一个OR

SELECT p.VORNA AS firstName, 
       p.NACHN AS lastName, 
       p.USRID AS [USER], 
       o.ORGEH AS OUID, 
       o.STEXT AS OU, 
       a.HolidayDate AS absentFrom, 
       a.HolidayDate AS absentUntil, 
       k.MessageDate AS actionDate,
       'holiday' as reason
  FROM Kondor_User_Activities AS k       
  JOIN Kondor_Users AS u 
        ON u.Users_Id = k.Users_Id 
  JOIN Kondor_UsersGrp AS g 
        ON g.UsersGrp_Id = u.UsersGrp_Id 
       and (   g.UsersGrp_ShortName <  'UA_' 
            OR g.UsersGrp_ShortName >= 'UA`')
  JOIN Kondor_Cities AS c 
        ON c.Cities_Id = isnull(u.Cities_Id, g.Cities_Id)
  JOIN Kondor_FixedHolidays AS a 
        ON a.Cities_Id = c.Cities_Id
       AND k.MessageDate >= a.HolidayDate 
       and k.MessageDate <  a.HolidayDateEnd 

  JOIN dbo.SAP_Personaldaten AS p 
        ON p.USRID = k.Code 
  JOIN SAP_OE AS o 
        ON p.ORGEH = o.ORGEH 

答案 3 :(得分:0)

作为一个盲目的远射 - 没有桌子,关系,索引或任何有用的东西,试试这个:

getArguments().getString("String");

不知道我是否正确地击中了所有列名,但我认为这里的问题是优化器发狂并因为条件的复杂性说:“我要去一排测试每个用户活动的时间,看它是否符合所有其他标准“。

我的努力是将查询的逻辑部分分开 - 按此顺序:
 1.创建用户可以使用的所有城市 - 直接指定或从组( SELECT UActivities.firstName, UActivities.lastName, UActivities.[USER], UActivities.OUID, UActivities.OU, UserHoliday.HolidayDate AS absentFrom, UserHoliday.HolidayDate AS absentUntil, UActivities.actionDate, 'holiday' as reason FROM ( SELECT k.MessageDate AS actionDate, k.Users_Id, k.Code, p.VORNA AS firstName, p.NACHN AS lastName, p.USRID AS [USER], o.ORGEH AS OUID, o.STEXT AS OU FROM Kondor_User_Activities AS k INNER JOIN dbo.SAP_Personaldaten AS p ON k.Code = p.USRID INNER JOIN SAP_OE AS o ON p.ORGEH = o.ORGEH ) AS UActivities INNER JOIN ( SELECT UserCities.Users_Id, a.HolidayDate FROM ( SELECT u.Users_Id, ISNULL(u.Cities_Id, g.Cities_Id) AS CityId FROM Kondor_Users u INNER JOIN Kondor_UsersGrp AS g ON g.UsersGrp_Id = u.UsersGrp_Id AND (g.UsersGrp_ShortName NOT LIKE 'UA_%') ) AS UserCities INNER JOIN Kondor_FixedHolidays AS a ON a.Cities_Id = UserCities.CityId ) AS UserHoliday ON UActivities.Users_Id = UserHoliday.Users_Id AND UActivities.actionDate >= UserHoliday.HolidayDate and UActivities.actionDate < UserHoliday.HolidayDateEnd )继承  2.根据从#1获得的城市创建所有假期  3.从其他表中加入那些需要的用户数据。

看看这个结果 - 也许最好不要创建ISNULL(u.Cities_Id, g.Cities_Id)内部查询,而是将这些表从它加入到UActivities的结果中。要确定这一点,我真的需要访问 - 但你可以做到。

运行前检查计划。在阅读方面应该有很多不同和更平衡。