已掉线,重新登录

首页 > 绿虎论坛 > 历史版块 > 编程 > 数据库

如何用 SQL 求出「都关注了某100人」和「都收藏了某100帖子」的所有用户?


『回复列表(165|显示机器人聊天)』

80.

@无名啊,执行优化可能不蠢,但只是可能,调查研究需要时间。所以我何不把可能性掐灭在萌芽中,给它一定不蠢的SQL语句呢?

(/@Ta/2022-08-11 15:11//)

81.

@老虎会游泳,唉,可惜 SQL 本就是个声明式编程语言,大部分时候命运就是要交给别人掌控

(/@Ta/2022-08-11 15:15//)

82.

@无名啊,而且我觉得单个复杂SQL语句的可读性也没有拼接SQL来的清晰。还有,如果你使用封装好的数据库操作类,那么背后肯定是拼接SQL,不会是预先生成的复杂语句。

比如

function 搜索($名称, $手机) {
    if (empty($名称) && empty($手机)) {
        return null;
    }
    $db = new 数据库操作类();
    $table = $db->select('用户信息表');
    if (!empty($名称)) {
        $table->where('名称', '=', $名称);
    }
    if (!empty($手机)) {
        $table->where('手机', '=', $手机);
    }
    return $table->query();
}

这样的代码背后肯定是拼接SQL+预处理,没有单个复杂SQL的存在。

(/@Ta/2022-08-11 15:36//)

83.

@无名啊

可惜 SQL 本就是个声明式编程语言,大部分时候命运就是要交给别人掌控

我的原则是,能不交给SQL的,就不交给SQL。绝不把它当做编程语言,能不在它里面做的运算就不在它里面做。

毕竟运行网站的web服务器可扩展而且很容易扩展,但MySQL很难扩展。

(/@Ta/2022-08-11 15:28//)

84.

@无名啊,对了,关于标题

「都关注了某100人」和「都收藏了某100帖子」的所有用户

不用查了,直接返回null就好了。100个相同,怎么可能?哪有那么巧。

(/@Ta/2022-08-11 15:41//)

85.

@老虎会游泳,标题就是个方便理解『抽象概念』的『具体例子』,我刷刷刷写一堆抽象名词,有谁愿意看呐。。

(/@Ta/2022-08-11 15:43//)

86.

@老虎会游泳,要写抽象概念,也要先骗进来再上啊

(/@Ta/2022-08-11 15:45//)

87.

@无名啊,我只是想指出,实际的搜索词应该不会有100个那么多。所以拼接SQL带来的性能影响应该可以忽略不计。

然后再看你的限定条件:

注意:
尽量不要使用存储过程/函数、其他编程语言,以及 MySQL 8.0.17+ 的多值索引。
尽量使用 B+ 树索引(好像PostgreSQL有针对json的高效索引)

好像符合这个条件的也只有

SELECT * FROM 员工信息表 WHERE
        员工ID IN (SELECT 员工ID FROM 员工技能表 WHERE 技能 = '技能1')
    AND 员工ID IN (SELECT 员工ID FROM 员工技能表 WHERE 技能 = '技能2')
    AND 员工ID IN (SELECT 员工ID FROM 员工手机表 WHERE 手机 = '手机1')
    AND 员工ID IN (SELECT 员工ID FROM 员工手机表 WHERE 手机 = '手机2');

因为JSON_CONTAINS是函数,并且使用多值索引

(/@Ta/2022-08-11 15:46//)

88. @老虎会游泳,我想到的场景是,楼主是 FBI,正在通过某人零碎的信息,在数据库中筛选得出这个人的具体身份
(/@Ta/2022-08-11 15:48//)

89.

@老虎会游泳

我的原则是,能不交给SQL的,就不交给SQL。绝不把它当做编程语言,能不在它里面做的运算就不在它里面做。

我有所耳闻,特别是涉及分库分表时

但我希望,我有能力真的分辨清楚咯:压力真的能传到应用层服务器去

而不是盲目全放在其他服务器干,数据库整体相比原来:

  1. 该干的活儿,一样没少干
  2. 还多了不必要的压力
    • select 出多余数据
    • 传输过多数据
    • ……
(/@Ta/2022-08-11 15:53//)

90.

@老虎会游泳,那个『关系除法』没使用JSON_CONTAINS呀,也没有多值索引,能放到SQLite上运行

(/@Ta/2022-08-11 15:51//)

91.

@无名啊,嗯确实,但长度太可怕了

又是JOIN又是GROUP BY的,它真的能高效运行吗?

WITH

  除以要求技能表(员工ID) AS (
    SELECT DISTINCT 员工ID
      FROM 员工技能表 AS ES1
     WHERE NOT EXISTS (
               SELECT *
                 FROM 要求技能表
                WHERE NOT EXISTS (
                          SELECT *
                            FROM 员工技能表 AS ES2
                           WHERE ES2.员工ID = ES1.员工ID
                             AND ES2.技能 = 要求技能表.技能 ))
  ),
  
  除以要求手机表(员工ID) AS (
    SELECT DISTINCT 员工ID
      FROM 员工手机表 AS ES1
     WHERE NOT EXISTS (
               SELECT *
                 FROM 要求手机表
                WHERE NOT EXISTS (
                          SELECT *
                            FROM 员工手机表 AS ES2
                           WHERE ES2.员工ID = ES1.员工ID
                             AND ES2.手机 = 要求手机表.手机 ))
  )

-- 如果要显示员工详细信息的话
SELECT 员工表.*
  FROM 除以要求技能表
  JOIN 除以要求手机表 USING(员工ID)
  JOIN 员工表 USING(员工ID)
 GROUP BY 员工ID;
(/@Ta/2022-08-11 15:53//)

92.

@老虎会游泳,生成点儿随机数据试试?

(/@Ta/2022-08-11 15:54//)

93.

@无名啊,你来试试呗,我没有测试环境

(/@Ta/2022-08-11 15:55//)

94.

@老虎会游泳,我发现,现在我已经把SQLite等同于一般SQL了。。

SQLite 都能支持,其他数据库凭啥用不了?!

的态度。。

(但近一两个月,SQLite支持FULL OUTER JOIN了。。现在压力给到MySQL

(/@Ta/2022-08-11 15:58//)

95.

@老虎会游泳,你觉得这两坨除以要求技能表除以要求手机表能优化合并吗?

(我主要就是想优化合并这个 SQL 的。。)

(/@Ta/2022-08-11 16:06//)

96.

@老虎会游泳,《SQL 解惑(第二版)》谜题 21 飞机与飞行员,也提到过类似问题。但他是只有一个条件的:

有一个表包含飞行员和他们能够驾驶的飞机,还有一个表包含停在飞机棚中的飞机。需要找出能够驾驶飞机棚中每一架飞机的飞行员姓名。

别人除了用『关系除法』外,还用了另一种简短一些的方法

SELECT 飞行员
  FROM 飞行员会开啥飞机表 AS PS, 停在飞机棚的飞机表 AS H
 WHERE PS.飞机 = H.飞机
 GROUP BY PS.飞行员
HAVING COUNT(PS.飞机) = (SELECT COUNT(*) FROM 停在飞机棚的飞机表)

哪个方法快?别人实验总结:

COUNT(结果) < COUNT(飞行员会开啥飞机表) * 0.25 时,『关系除法』较好,否则上面的方法好

飞行员会开啥飞机表

飞行员 飞机
Celko Piper Cub
Higgins B-52 Bomber
Higgins F-14 Fighter
Higgins Piper Cub
Jones B-52 Bomber
Jones F-14 Fighter
Smith B-1 Bomber
Smith B-52 Bomber
Smith F-14 Fighter
Wilson B-1 Bomber
Wilson B-52 Bomber
Wilson F-14 Fighter
Wilson F-17 Fighter

停在飞机棚的飞机表

飞机
B-1 Bomber
B-52 Bomber
F-14 Fighter

答案

飞行员
Smith
Wilson
(/@Ta/2022-08-11 16:23//)

97.

@无名啊,仿写一个:

公共聊天室文件上传发过言,并且在超级灌水网页插件版块发过帖的用户:

SELECT c3.uid
FROM
(
    SELECT uid FROM
    (
        SELECT uid, count(*) as c FROM 
        (
            SELECT DISTINCT uid, room
            FROM hu60_addin_chat_data
            WHERE room IN ('公共聊天室', '文件上传')
        ) c1
        GROUP BY uid
    ) c2
    WHERE c = 2
) c3
INNER JOIN
(
    SELECT uid FROM
    (
        SELECT uid, count(*) as c FROM 
        (
            SELECT DISTINCT uid, forum_id
            FROM hu60_bbs_topic_meta
            WHERE forum_id IN (
                SELECT id
                FROM hu60_bbs_forum_meta
                WHERE name IN ('超级灌水', '网页插件')
            )
        ) f1
        GROUP BY uid
    ) f2
    WHERE c = 2
) f3
ON
    c3.uid=f3.uid

截图_选择区域_20220811185938.png(307.73 KB)

(/@Ta/2022-08-11 19:00//)

98.

用HAVING子句减少一层嵌套:

公共聊天室文件上传发过言,并且在超级灌水网页插件版块发过帖的用户:

SELECT c2.uid
FROM
(
    SELECT uid FROM 
    (
        SELECT DISTINCT uid, room
        FROM hu60_addin_chat_data
        WHERE room IN ('公共聊天室', '文件上传')
    ) c1
    GROUP BY uid
    HAVING count(*) = 2
) c2
INNER JOIN
(
    SELECT uid FROM 
    (
        SELECT DISTINCT uid, forum_id
        FROM hu60_bbs_topic_meta
        WHERE forum_id IN (
            SELECT id
            FROM hu60_bbs_forum_meta
            WHERE name IN ('超级灌水', '网页插件')
        )
    ) f1
    GROUP BY uid
    HAVING count(*) = 2
) f2
ON
    c2.uid=f2.uid

截图_选择区域_20220811190027.png(286.57 KB)

(/@Ta/2022-08-11 19:00//)

99.

比这种写法慢很多啊:

SELECT uid, name FROM hu60_user WHERE
        uid IN (SELECT DISTINCT uid FROM hu60_addin_chat_data WHERE room = '公共聊天室')
    AND uid IN (SELECT DISTINCT uid FROM hu60_addin_chat_data WHERE room = '文件上传')
    AND uid IN (SELECT DISTINCT uid FROM hu60_bbs_topic_meta WHERE forum_id = (
            SELECT id FROM hu60_bbs_forum_meta WHERE name = '超级灌水'
        ))
    AND uid IN (SELECT DISTINCT uid FROM hu60_bbs_topic_meta WHERE forum_id = (
            SELECT id FROM hu60_bbs_forum_meta WHERE name = '网页插件'
        ));

截图_选择区域_20220811185435.png(399.60 KB)

(/@Ta/2022-08-11 18:56//)

下一页 上一页 5/9页,共165楼

回复需要登录

10月7日 21:50 星期二

本站由hu60wap6驱动

备案号: 京ICP备18041936号-1