已掉线,重新登录

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

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


『回复列表(165|隐藏机器人聊天)』

100.

试试这样写

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

和上面的写法没有差别,可能最终的执行方式是一样的。

截图_选择区域_20220811184940.png(409.13 KB)

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

101.

用关系除法试试

CREATE TEMPORARY TABLE 要求聊天室表(room varchar(255));
INSERT INTO 要求聊天室表 VALUES('公共聊天室'), ('文件上传');

CREATE TEMPORARY TABLE 要求论坛表(forum_id int);
INSERT INTO 要求论坛表 SELECT id FROM hu60_bbs_forum_meta WHERE name IN ('超级灌水', '网页插件');

SELECT hu60_user.uid, hu60_user.name
  FROM (
    SELECT DISTINCT uid
      FROM hu60_addin_chat_data AS ES1
     WHERE NOT EXISTS (
               SELECT *
                 FROM 要求聊天室表
                WHERE NOT EXISTS (
                          SELECT *
                            FROM hu60_addin_chat_data AS ES2
                           WHERE ES2.uid = ES1.uid
                             AND ES2.room = 要求聊天室表.room ))
  ) AS 除以要求聊天室表
  JOIN (
    SELECT DISTINCT uid
      FROM hu60_bbs_topic_meta AS ES1
     WHERE NOT EXISTS (
               SELECT *
                 FROM 要求论坛表
                WHERE NOT EXISTS (
                          SELECT *
                            FROM hu60_bbs_topic_meta AS ES2
                           WHERE ES2.uid = ES1.uid
                             AND ES2.forum_id = 要求论坛表.forum_id ))
  ) AS 除以要求论坛表 USING(uid)
  JOIN hu60_user USING(uid)
 GROUP BY uid;

并不快

截图_选择区域_20220811184653.png(652.95 KB)

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

102.

@无名啊,现在我可以大胆的说,对于

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

这个问题,拼接WHERE条件的方法是最快的,比你的书上记载的两个方法快得多。而且关系除法是所有方法中最慢的。

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

103.

@老虎会游泳,我本地创建点儿大表试试(一千万用户ID x 15~25 个技能ID = 2亿行 员工技能表,足够吗?)

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

104.

@无名啊,我不知道,我没有大型数据集测试经验。

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

105.

@老虎会游泳,我也没有。。

PHP 能指定随机数种子不?我用 PHP 生成 csv,再导入 SQLite / MySQL

有这个种子,你那也能生成同样数据集

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

106.

@无名啊,mt_srand/mt_rand

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

107.

@老虎会游泳,用这个 php 随机生成两张约 2亿行的大表吧

分别输出至 STDOUT 和 STDERR,可以在 shell 中从这两处地方导入至两表

mt_srand(strtotime('2022-08-11 20:00:00'));

foreach ([STDOUT, STDERR] as $fp)
    for ($uid = 1; $uid <= 10000000; ++$uid)
        for ($i = mt_rand(15, 25); $i > 0; --$i)
            fprintf($fp, "%d,%d\n", $uid, mt_rand(0, 255));

可按索引需要调换字段顺序(反正数字一致):

fprintf($fp, "%d,%d\n", mt_rand(0, 255), $uid);
(/@Ta/2022-08-11 19:50//)

108.

@老虎会游泳,是不是还需要个 fclose($fp),来结束第一阶段的导入。。

另外,我这儿运行好慢啊,是不是哪儿写错了

光是这样都很慢:

php main.php 2>/dev/null | wc -c
(/@Ta/2022-08-11 19:56//)

109.

@无名啊,嗯,等你测试。我不能在hu60.cn进行此类测试,我没有其他测试环境。

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

110.

@无名啊,生成那么多行本来就不会快。

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

111.

@老虎会游泳,可以用 sqlite 试一试

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

112.

@老虎会游泳,我吃个饭,等会儿来

(/@Ta/2022-08-11 20:01//)

113.

@老虎会游泳,不行啊,运行了 15分钟,还没结束。。

肯定哪儿写错了

(/@Ta/2022-08-11 20:12//)

114.

@老虎会游泳

PID USER       PRI  NI  VIRT   RES   SHR S  CPU% MEM%   TIME+  Command△
435 user        20   0 86604 14316  9456 R 101.0  0.2 17:10.31       ├─ php /mnt/c/Users/wuxun/PhpstormProjects/untitled/main.php
436 user        20   0 13464   780   652 R  98.3  0.0 16:44.55       └─ wc -c
(/@Ta/2022-08-11 20:15//)

115.

@无名啊,只是慢而已

Screenshot_20220811_210045_com.termux.jpg(420.50 KB)

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

116.

@无名啊,并行生成再合并文件可能是个好主意。多开几个进程,每个生成一部分。

(/@Ta/2022-08-11 21:01//)

117.

@老虎会游泳,我换其他语言试试了,要不生成一次太久,想换下范围(如 0~255 -> 0~ 65535),重新生成一次估计都得半个钟

Python 花了三分多钟

from datetime import datetime
from random import seed, randint

seed(int(datetime.fromisoformat('2022-08-11 20:00:00').timestamp()))

for uid in range(1, 10000000 + 1):
    for i in range(randint(15, 25)):
        print(f'{uid},{randint(0, 255)}')

运行:

$ time python3 /mnt/c/Users/wuxun/PycharmProjects/pythonProject/main.py | wc -c
2291797342

real    3m42.934s
user    3m42.000s
sys     0m2.875s
(/@Ta/2022-08-11 21:09//)

118.

@老虎会游泳,卧槽!!tcc牛逼啊!直接运行 C 源码,速度都能这么快!

randint 范围有点问题,修复了

$ time tcc -run - <<EOF | wc -c
#include <time.h>
#include <stdio.h>
#include <stdlib.h>

static inline int randint(int min, int max) {
    return rand() % (max - min + 1) + min;
}

int main() {

    srand(mktime(&(struct tm){
        .tm_year = 2022 - 1900,
        .tm_mon = 8 - 1,
        .tm_mday = 11,
        .tm_hour = 20,
        .tm_min = 0,
        .tm_sec = 0,
    }));

    for (int uid = 1; uid <= 10000000; ++uid)
        for (int i = randint(15, 25); i > 0; --i)
            printf("%d,%d\n", uid, randint(0, 255));
}
EOF

结果:

2291774656

real    0m22.888s
user    0m22.547s
sys     0m4.516s
(/@Ta/2022-08-11 22:10//)

119.

@老虎会游泳,我记得tcc是边解释边运行的啊,测下来 20秒 生成 2亿行。。

又不用编译,又不生成临时文件,以后就用 tcc 来解决脚本中的性能敏感部分了

$ time tcc -run main.c | wc -l
199993434

real    0m22.912s
user    0m24.016s
sys     0m4.422s
(/@Ta/2022-08-11 22:23//)

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

回复需要登录

7月6日 05:14 星期天

本站由hu60wap6驱动

备案号: 京ICP备18041936号-1