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?
答案 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
的结果中。要确定这一点,我真的需要访问 - 但你可以做到。
运行前检查计划。在阅读方面应该有很多不同和更平衡。