优化联合SQL查询

时间:2015-06-03 08:46:05

标签: mysql pdo query-optimization union

我有一个大查询,其中包含我在我的应用中列出的Feed所需的相同类型。现在问题是这个查询不是很快。我认为,如果我限制每个人的联盟,它可能会加快一点,但我不确定。

所以基本上我的问题是如何优化此查询以更快地执行?

SELECT DISTINCT 
      alert_id, 
      uniquekey, 
      type, 
      user_id, 
      date_added 
   FROM 
   (
     ( SELECT 
             r.alert_id, 
             r.alert_id AS uniquekey, 
             'reply' AS `type`,
             r.user_id, 
             r.date_added
          FROM 
             `reply` r 
                LEFT JOIN `alerts` a
                   ON r.alert_id = a.alert_content_id  
          WHERE 
                 r.user_id = :id 
             AND a.hide = '0'
          ORDER BY 
             date_added DESC )
     UNION
     ( SELECT 
             r.alert_id, 
             r.alert_id AS uniquekey, 
             'replyfromfollowing' AS `type`,
             r.user_id, 
             r.date_added
          FROM 
             `reply` r 
                LEFT JOIN `alerts` a
                   ON r.alert_id = a.alert_content_id 
          WHERE 
                 r.user_id IN( '$followingstring' ) 
             AND a.hide = '0'
            ORDER BY date_added DESC )
     UNION 
     ( SELECT 
             i.alert_id, 
             i.alert_id AS uniquekey, 
             'liked' AS `type`,
             i.user_id, 
             i.date_added 
          FROM 
             `interactions` i 
                LEFT JOIN `alerts` a
                   ON i.alert_id = a.alert_content_id 
          WHERE 
                 i.user_id = :id 
             AND a.hide = '0'
          GROUP BY 
             alert_id
          ORDER BY 
             date_added DESC )
     UNION 
     ( SELECT 
             i.alert_id, 
             i.alert_id AS uniquekey, 
             'likedfromfollowing' AS `type`,
             i.user_id, 
             i.date_added 
          FROM 
             `interactions` i 
                LEFT JOIN `alerts` a
                   ON i.alert_id = a.alert_content_id
          WHERE 
                 i.user_id IN ( '$followingstring' ) 
             AND a.hide = '0'
          GROUP BY 
             alert_id
          ORDER BY 
             date_added DESC ) 
     UNION 
     ( SELECT 
             alerts as alert_id,
             alert_content_id AS uniquekey,
             'following' AS `type`,
             user_id, 
             date_added 
          FROM 
             alerts a 
                LEFT JOIN `alerts_content` ac 
                   ON ac.id = a.alert_content_id 
          WHERE 
                 a.user_id IN ( '$followingstring' ) 
             AND ac.anoniem = '0' 
             AND a.hide = '0' 
          GROUP BY 
             alert_id 
          ORDER BY 
             date_added DESC )
      ) joined 
   GROUP BY 
      uniquekey 
   ORDER BY 
      date_added DESC 
   LIMIT 
      ".(int)$start.",20"

表格结构

Reply table Structure:
id
user_id
alert_id
description
reply_on_alert
reply_on_reply
date_added

Interaction table Structure:
id
alert_id
action_id
reply_id
user_id
date_added

Alerts table structure(Yes i know BIG mistake naming `id` : `alerts`):
alerts
title
alert_content_id
user_id
cat
lat
lon
state
hide
date_added

alerts_content table structure:
id
alert_id
description
img

查询结果:

Array
(
    [0] => Array
        (
            [alert_id] => 173404
            [uniquekey] => 173404
            [type] => reply
            [user_id] => 2
            [date_added] => 2015-06-01 16:34:16
        )

    [1] => Array
        (
            [alert_id] => 172174
            [uniquekey] => 172174
            [type] => replyfromfollowing
            [user_id] => 1380
            [date_added] => 2015-06-01 16:01:04
        )

    [2] => Array
        (
            [alert_id] => 171772
            [uniquekey] => 171772
            [type] => liked
            [user_id] => 2
            [date_added] => 2015-06-01 15:58:44
        )

    [3] => Array
        (
            [alert_id] => 149423
            [uniquekey] => 149423
            [type] => reply
            [user_id] => 2
            [date_added] => 2015-06-01 15:25:56
        )

    [4] => Array
        (
            [alert_id] => 164742
            [uniquekey] => 164742
            [type] => reply
            [user_id] => 2
            [date_added] => 2015-05-12 09:46:39
        )

    [5] => Array
        (
            [alert_id] => 163344
            [uniquekey] => 163344
            [type] => replyfromfollowing
            [user_id] => 3
            [date_added] => 2015-05-12 09:44:46
        )

    [6] => Array
        (
            [alert_id] => 164205
            [uniquekey] => 164205
            [type] => liked
            [user_id] => 2
            [date_added] => 2015-05-11 11:06:39
        )

    [7] => Array
        (
            [alert_id] => 160890
            [uniquekey] => 160890
            [type] => replyfromfollowing
            [user_id] => 1380
            [date_added] => 2015-05-08 14:29:34
        )

    [8] => Array
        (
            [alert_id] => 163002
            [uniquekey] => 163002
            [type] => replyfromfollowing
            [user_id] => 1380
            [date_added] => 2015-05-08 13:31:12
        )

    [9] => Array
        (
            [alert_id] => 159123
            [uniquekey] => 159123
            [type] => replyfromfollowing
            [user_id] => 48
            [date_added] => 2015-04-30 15:10:32
        )

    [10] => Array
        (
            [alert_id] => 150546
            [uniquekey] => 150546
            [type] => replyfromfollowing
            [user_id] => 16
            [date_added] => 2015-04-21 21:52:49
        )

    [11] => Array
        (
            [alert_id] => 149497
            [uniquekey] => 149497
            [type] => reply
            [user_id] => 2
            [date_added] => 2015-04-10 15:19:06
        )

    [12] => Array
        (
            [alert_id] => 141078
            [uniquekey] => 141078
            [type] => liked
            [user_id] => 2
            [date_added] => 2015-04-10 15:15:32
        )

    [13] => Array
        (
            [alert_id] => 125466
            [uniquekey] => 125466
            [type] => replyfromfollowing
            [user_id] => 3
            [date_added] => 2015-04-09 00:15:22
        )

    [14] => Array
        (
            [alert_id] => 134592
            [uniquekey] => 134592
            [type] => replyfromfollowing
            [user_id] => 3
            [date_added] => 2015-04-09 00:11:04
        )

    [15] => Array
        (
            [alert_id] => 124194
            [uniquekey] => 124194
            [type] => likedfromfollowing
            [user_id] => 3
            [date_added] => 2015-04-09 00:08:35
        )

    [16] => Array
        (
            [alert_id] => 128645
            [uniquekey] => 128645
            [type] => likedfromfollowing
            [user_id] => 3
            [date_added] => 2015-04-09 00:07:29
        )

    [17] => Array
        (
            [alert_id] => 144867
            [uniquekey] => 144867
            [type] => replyfromfollowing
            [user_id] => 3
            [date_added] => 2015-04-06 13:59:19
        )

    [18] => Array
        (
            [alert_id] => 133355
            [uniquekey] => 133355
            [type] => liked
            [user_id] => 2
            [date_added] => 2015-03-31 16:16:15
        )

    [19] => Array
        (
            [alert_id] => 141075
            [uniquekey] => 141075
            [type] => liked
            [user_id] => 2
            [date_added] => 2015-03-30 15:17:01
        )

)

1 个答案:

答案 0 :(得分:1)

一些可能性,没有特别的顺序:

优化#1:

在子查询中也使用LIMIT。但是,由于您使用的是OFFSET,因此可能并不明白如何操作。

在查询之前,计算$ start + 20并将其放入,例如$ limit。然后使用LIMIT $limit进行内部查询。不,不要在他们身上使用OFFSET。这可以保证您从每个查询中获得足够的行以满足外部OFFSET $start LIMIT 20

优化#2:

重组表格,以便您不需要JOIN到另一个表格(alerts)以查明是否显示记录。也就是说,hide阻止了许多潜在的优化。在进一步建议之前,我们需要了解LEFT的必要性。 reply等中的行是否在alerts中?如果没有,请删除LEFT并查看搜索alerts with the OFFSET and LIMIT`,然后加入其他4个表。

优化#3:

重组数据,以便有一个核心表,其中alerts和其他4个表挂在上面。请确保在此新表中包含查询所需的大多数(全部?)字段。

优化#4:

当前结构要求在考虑OFFSETLIMIT之前对4个表中的每个表进行全面扫描。这闻起来像"分页&#34 ;;是吗?为了优化"分页",目标是避免表格扫描和OFFSET;而是记住你离开的地方"这样查询就可以

WHERE ... AND x < $left_off
ORDER by x DESC
LIMIT 20

这应该可以只读取20行,而不是整个表。这将使查询更多更快,尤其是对于以后的页面。 (OFFSET更大的时间会花费更多的时间。)

我在my blog讨论分页优化。