大表查询运行非常慢

时间:2019-12-26 15:41:37

标签: sql optimization sql-server-2016

具有以下2个表:

MainProcessed

Id  Value
---------
1   123
2   234
3   112

MainAdditionalInfo

Id  MainProcessedId Name    Value
--------------------------------------
1   1               'PX'    'px_value'
2   1               'PY'    'py_value'

我需要从表MainProcessedId中选择所有在表MainAdditionalInfo中具有一些附加信息的数据(至少一个记录),并且它没有名称为PX或如果有,则此值应为null或为空。

这是我尝试过的方法,但是由于这些表具有大量数据(超过1亿条记录,因此查询运行了很多时间):

select mp.*
from MainProcessed mp (nolock)
left join MainAdditionalInfo mai1 (nolock) on mp.Id = mai1.MainProcessedId
left join MainAdditionalInfo mai2 (nolock) on mp.Id = mai2.MainProcessedId
where
    (mai1.Value is null or mai1.Value = '')
    and (mai1.Name = 'PX' or mai1.Name = null)
    and mai2.name = 'PY'

请注意,名称为PX的值可能不存在或可以为空值或空值,但名称为PY的值始终存在。你能建议我改善吗?

此外,我无权查看执行计划或创建新对象(索引)。

4 个答案:

答案 0 :(得分:3)

您可以尝试用existsnot exists来短语查询:

select p.*
from MainProcessed p
where 
    exists (
        select 1 
        from MainAdditionalInfo a 
        where a.MainProcessedId = p.id)
    and not exists (
        select 1 
        from MainAdditionalInfo a 
        where 
            a.MainProcessedId = p.id 
            and a.Name = 'PX' 
            and a.Value <> ''    -- null values won't pass that test
    ) 

要获得此查询的性能,您需要在MainAdditionalInfo(MainProcessedId , Name, Value)上建立索引。

答案 1 :(得分:0)

select mp.*
from MainProcessed mp
left join MainAdditionalInfo mai1 on mp.Id = mai1.MainProcessedId and mai2.name ='PX'
where Id in(
    select distinct MainProcessedId
    from MainAdditionalInfo mai2
        inner join MainProcessed on Id = mai2.MainProcessedId and mai2.name ='PY'
    )
    and (mai1.Value is null or mai1.Value = '')

答案 2 :(得分:0)

这个评论太长了,但是我在扩展第二个评论。这也不能回答问题(问题中没有足够的细节来回答),但是无论如何它可能会帮助查询计划程序。

首先,您在WHERE中有2个子句,就像(mai1.Value is null or mai1.Value = '')假定,这是因为如果Value可能是NULL {1}}失败。如果是这样,请勿在您的JOIN中处理它,而将其放在WHERE中。

您也有ON,但是您对and mai2.name = 'PY'执行了LEFT JOIN。这意味着MainAdditionalInfo mai2现在是隐式JOIN。因此,我个人将您的查询写为:

INNER JOIN

我还删除了SELECT {List columns, do not use *} FROM MainProcessed mp JOIN MainAdditionalInfo mai2 ON mp.Id = mai2.MainProcessedId LEFT JOIN MainAdditionalInfo mai1 ON mp.Id = mai1.MainProcessedId AND mai1.Value = '' AND mai1.Name = 'PX' WHERE mai2.[name] = 'PY'; 提示,因为我怀疑它们弊大于利。 Bad habits : Putting NOLOCK everywhere

答案 3 :(得分:0)

首先,应确保在MainAdditionalInfoMainProcessed.ID上具有FK,索引在MainAdditionalInfo.MainProcessedId上。另外,您应该在MainAdditionalInfoname列的value上有一个索引。
如果您不需要join中的数据,请不要使用MainAdditionalInfo,请使用exists,例如:

SELECT mp.*
FROM MainProcessed mp (nolock)
WHERE NOT EXISTS (SELECT 1 FROM MainAdditionalInfo mai1
  WHERE mai1.Value > '' 
  AND mai1.Name = 'PX' 
  AND mp.Id = mai1.MainProcessedId)
AND EXISTS (SELECT 1 FROM MainAdditionalInfo mai2 
  WHERE mai2.name = 'PY' 
  AND mp.Id = mai2.MainProcessedId)