内部连接的 SQL 查询执行时间慢

Posted

技术标签:

【中文标题】内部连接的 SQL 查询执行时间慢【英文标题】:Slow SQL query execution time with inner joins 【发布时间】:2016-02-18 07:39:59 【问题描述】:

我使用的是 Microsoft SQL Server 企业版(64 位)。

我的查询执行时间大约是 1 分钟。

Docum 表有 xxxxxxxx 行 Pers 表有 xxxxxxx 行 Permarks 表有 xxxxxx 行

Docum 表上的索引:

Pers 表上的索引:

Permarks 表上的索引:

PERSMARKS_pm_p_id   
PERSON_MARKScode_AND_date_till_AND_end_date_

查询:

SELECT doc
FROM docum(NOLOCK)
INNER JOIN pers(NOLOCK) ON doc = p
INNER JOIN permarks(NOLOCK) ON pm = p
WHERE doccode IN (20, 21, 22, 23, 24, 25, 30) 
  AND pm_ = 14
  AND (enddate IS NULL OR enddate > getdate())
  AND (date_till IS NULL OR date_till > getdate())

如何加快查询速度?

这里是完整的查询,执行时间是 5 分钟 INTO #temp:

SELECT f
    ,0 AS viso
    ,count(DISTINCT p) AS el_budu
    ,0 AS vidinis
    ,0 AS pasirasyta
    INTO #temp
FROM documents(NOLOCK)
INNER JOIN fo(NOLOCK) ON doc = fv
INNER JOIN for(NOLOCK) ON fve = f
INNER JOIN per(NOLOCK) ON doc = p
INNER JOIN tax ti(NOLOCK) ON p = ti
INNER JOIN permarks(NOLOCK) ON pm = p
WHERE pmtcode = 14
    AND (
        enddate IS NULL
        OR enddate > getdate()
        )
    AND (
        datetill IS NULL
        OR datetill > getdate()
        )
    AND startdate >= '2015-01-01'
    AND enddate <= '2015-12-31'
    AND rtcode = 1
    AND fvcode IN (25)
    AND doccode IN (
        20
        ,21
        ,22
        ,23
        ,24
        ,25
        ,30
        )
GROUP BY fcode

执行计划结果:results photo

【问题讨论】:

doc_dprt_code 中有索引吗? 是的,我有两列 doc_dprt_code 和 doc_reg_date 的非聚集索引 您应该查看execution plan。顺便说一句,日期过滤器不好。 这很奇怪。然后向您的 DBA 询问计划。 停止破坏你的问题... 【参考方案1】:

在上图中,我用聚集/非聚集索引标记了列。如果上图中写有任何错误,请纠正我。我的观点如下: -

    您在表格文档和 person_marks 中是否有任何聚集索引。似乎它们上有所有非聚集索引。如果没有聚集索引,则非聚集索引必须从表中获取值,这很昂贵,并且您将无法获得良好的执行计划。

    如果值是唯一的,则尽可能在 pm_p_id 和 doc_p_id 上创建聚集索引。这将有助于优化器使用合并连接而不是哈希连接。

    利用#temp表

【讨论】:

1.是的,我在这些表中有聚集索引【参考方案2】:

为了便于阅读,我重新组织了您的查询。我还添加了 别名,因为它们出现在您的表中 应该是一个好习惯,尤其是对于那些 必须跟随/与您合作并了解数据的实际位置 来自无需询问表结构。

您正在加入 person 表,但没有真正使用任何东西 除了要加入的“p_id”之外的人的记录 person_marks 表。

SELECT 
      d.doc_p_id
   FROM 
      documents d (NOLOCK)
         INNER JOIN persons p (NOLOCK) 
            ON d.doc_p_id = p.p_id
            INNER JOIN person_marks pm (NOLOCK) 
               ON p.p_id = pm.pm_p_id 
              AND pm.pm_pmt_code = 14
              AND (pm.pm_end_date IS NULL OR pm.pm_end_date > getdate())
              AND (pm.pm_date_till IS NULL OR pm.pm_date_till > getdate())
   WHERE 
      d.doc_dprt_code IN (20, 21, 22, 23, 24, 25, 30) 

通过传递过程,如果文档“doc_p_id”是人 id,然后那个可以直接去person_marks表 无需加入将其完全从混合中删除的人员 (除非这只是一个样本,你会抓住个人 信息稍后用于生产查询)。

SELECT 
      d.doc_p_id
   FROM 
      documents d (NOLOCK)
         INNER JOIN person_marks pm (NOLOCK) 
            ON d.doc_p_id = pm.pm_p_id 
           AND pm.pm_pmt_code = 14
           AND (pm.pm_end_date IS NULL OR pm.pm_end_date > getdate())
           AND (pm.pm_date_till IS NULL OR pm.pm_date_till > getdate())
   WHERE 
      d.doc_dprt_code IN (20, 21, 22, 23, 24, 25, 30) 

接下来,对于索引,我会推荐以下表/索引 覆盖查询条件的索引,因此它没有 去实际的数据页面来解析条目。

table          index
documents      ( doc_dprt_code, doc_p_id )
person_marks   ( pm_p_id, pm_pmt_code, pm_end_date, pm_date_till )

最后,由于您(目前)只获取人员 ID,您可能需要更改为

select DISTINCT d.doc_p_id ...

因此它每人只返回一条记录(同样,除非您实际上是在获取其他数据并且只是为了发布/支持目的而简化查询)。

【讨论】:

是的,这是一个样本,我需要 person 表来获取 p_legal_count,所有索引都存在

以上是关于内部连接的 SQL 查询执行时间慢的主要内容,如果未能解决你的问题,请参考以下文章

mysql数据库: 为啥sql语句在查询分析中的执行速度远远快于在应用程序的(而且有时候后者慢的很多)

慢查询日志和profiling

与 wp_postmeta 连接的 wp_posts 内部的 Wordpress 慢查询

性能测试四十一:慢sql和执行计划一

mysql数据库查询好慢怎么解决

MySQL中如何查看“慢查询”,如何分析执行SQL的效率?