mysql - 优化联合 SQL 查询

标签 mysql pdo query-optimization union

我有一个大查询,所有查询都包含我在应用程序中列出的提要所需的相同类型。现在的问题是这个查询不是很快。我在想,如果我限制每个单独的工会,可能会加快速度,但我不确定。

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

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:

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

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

优化#2:

重构表,以便您无需JOIN到另一个表(alerts)来确定是否显示记录。也就是说,隐藏会阻止许多潜在的优化。在提供进一步建议之前,我们需要了解 LEFT 的需求。 reply 等中是否存在 alerts 中没有的行?如果没有,请删除LEFT并使用OFFSETLIMIT`搜索警报,然后加入其他4个表。

优化#3:

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

优化#4:

当前的结构需要在考虑 OFFSETLIMIT 之前对 4 个表中的每一个进行全面扫描。这听起来像“分页”;是吗?为了优化“分页”,目标是避免表扫描和 OFFSET;相反,请记住您“停止”的位置,以便查询可以

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

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

我在 my blog 中讨论分页优化.

关于mysql - 优化联合 SQL 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30615076/

相关文章:

php - 选择不同表的两列之间的差/减

performance - 主动跟踪 Oracle 查询性能

mysql - UPDATE 字段从表 1 到表 2,其中连接它们的字段在表 2 中不是唯一的

php - 评论删除按钮不起作用

php - MYSQL 查询 - 基于同一表中另一列中的 DISTINCT 值从一列返回所有值的简单方法?

mysql - 提高 MySQL 查询速度 - 返回 150,000 多行会减慢查询速度

mysql 性能问题

Erlang 中的 Mysql

sql - 清理数据源

MySQL current_insert_id()? (不是 last_insert_id())