mysql - 立即从表 AND 'archive' 表中选择

标签 mysql sql

为了减小其中一个表的大小(目前超过 400 万行),我创建了一个“存档”表,该表只能由某些用户访问。

归档表是主表的副本,只不过它包含很少被访问的旧行。

但是,有时我需要查询两个表:

SELECT 
    t1.*, 
    t6.*
FROM (
    SELECT 
        COUNT(DISTINCT up.lesson_id) AS assessment_count, 
        MIN(up.date) AS first_date, 
        MAX(up.date) AS last_date
    FROM 
        cdu_user_progress up
    WHERE 
        (up.game_id = '0') AND 
        (up.uid = '150') AND 
        (up.lesson_id IN  ('65', '1112', '66', '67', '68', '69', '1114', '70', '71', '72', '73', '74', '75', '1113', '77', '424', '423', '1115', '93', '94', '95', '420', '421', '422', '96', '97', '98', '99', '100', '101', '1015', '102', '415', '104', '106', '105', '107', '108', '1016', '109', '110', '160', '111', '113', '112', '738', '739', '1050', '1051', '116', '117', '118', '119', '120', '121', '1017', '123', '124', '125', '130', '1018', '131', '148', '149', '150', '151', '152', '153', '154', '155', '156', '157', '158', '159', '171', '172', '173', '174', '175', '176', '177', '178', '179', '180', '181', '182', '267', '268', '269', '270', '271', '272', '273', '274', '1019', '278', '775', '279', '280', '281', '282', '283', '284', '285', '286', '1161', '287', '288', '289', '290', '291', '292', '293', '294', '295', '296', '297', '298', '299', '300', '301', '318', '319', '302', '303', '304', '305', '306', '307', '308', '309', '337', '338', '339', '340', '341', '342', '343', '344', '345', '346', '1054', '347', '348', '349', '350', '351', '352', '353', '354', '355', '356', '377', '378', '379', '380', '479', '480', '481', '482', '431', '432', '433', '434', '435', '436', '437', '438', '439', '440', '441', '442', '443', '444', '445', '446', '448', '447', '449', '450', '451', '452', '453', '454', '456', '455', '457', '458', '459', '460', '461', '462', '463', '464', '465', '466', '467', '468', '469', '470', '471', '472', '473', '474', '475', '476', '477', '478', '1090')) AND 
        (up.score > '-1')
) t1
INNER JOIN (
    SELECT 
        AVG(c1.score) AS avg_first_scores, 
        SUM(c1.score) AS sum_first_scores
    FROM 
        cdu_user_progress c1
    LEFT OUTER JOIN cdu_user_progress c2 ON c1.uid = c2.uid AND c1.lesson_id = c2.lesson_id AND c1.game_id = c2.game_id AND c1.level = c2.level AND c1.date > c2.date AND c2.score > -1
    WHERE  
        (c1.game_id = '0') AND 
        (c1.uid = '150') AND 
        (c1.lesson_id IN  ('65', '1112', '66', '67', '68', '69', '1114', '70', '71', '72', '73', '74', '75', '1113', '77', '424', '423', '1115', '93', '94', '95', '420', '421', '422', '96', '97', '98', '99', '100', '101', '1015', '102', '415', '104', '106', '105', '107', '108', '1016', '109', '110', '160', '111', '113', '112', '738', '739', '1050', '1051', '116', '117', '118', '119', '120', '121', '1017', '123', '124', '125', '130', '1018', '131', '148', '149', '150', '151', '152', '153', '154', '155', '156', '157', '158', '159', '171', '172', '173', '174', '175', '176', '177', '178', '179', '180', '181', '182', '267', '268', '269', '270', '271', '272', '273', '274', '1019', '278', '775', '279', '280', '281', '282', '283', '284', '285', '286', '1161', '287', '288', '289', '290', '291', '292', '293', '294', '295', '296', '297', '298', '299', '300', '301', '318', '319', '302', '303', '304', '305', '306', '307', '308', '309', '337', '338', '339', '340', '341', '342', '343', '344', '345', '346', '1054', '347', '348', '349', '350', '351', '352', '353', '354', '355', '356', '377', '378', '379', '380', '479', '480', '481', '482', '431', '432', '433', '434', '435', '436', '437', '438', '439', '440', '441', '442', '443', '444', '445', '446', '448', '447', '449', '450', '451', '452', '453', '454', '456', '455', '457', '458', '459', '460', '461', '462', '463', '464', '465', '466', '467', '468', '469', '470', '471', '472', '473', '474', '475', '476', '477', '478', '1090')) AND 
        (c1.score > '-1') AND 
        (c2.date IS '')  
) t6

我已经想到的解决方案 - 将 SELECT cdu_user_progress 替换为嵌套查询:

SELECT * FROM cdu_user_progress UNION SELECT * FROM cdu_user_progress_archive

但这会在内存中创建一个巨大的临时表。

我尝试了每个查询的 UNION(上面的嵌套查询),但这会导致返回多行,而过去它只返回单行。

SELECT 
    ...
FROM (
    SELECT 
        ...
    FROM 
        cdu_user_progress up
    WHERE 
        ...
    UNION SELECT 
        ...
    FROM 
        cdu_user_progress_archive up
    WHERE 
        ...
) t1
INNER JOIN (
    SELECT 
        ...
    FROM 
        cdu_user_progress c1
    LEFT OUTER JOIN cdu_user_progress c2 ON c1.uid = c2.uid AND c1.lesson_id = c2.lesson_id AND c1.game_id = c2.game_id AND c1.level = c2.level AND c1.date > c2.date AND c2.score > -1
    WHERE  
        ...
    UNION SELECT 
        ...
    FROM 
        cdu_user_progress_archive c1
    LEFT OUTER JOIN cdu_user_progress_archive c2 ON c1.uid = c2.uid AND c1.lesson_id = c2.lesson_id AND c1.game_id = c2.game_id AND c1.level = c2.level AND c1.date > c2.date AND c2.score > -1
    WHERE  
        ...
) t6

还有其他想法吗???

谢谢!

最佳答案

这些 suq 查询包含聚合。

因此,一个简单的解决方案就是违反 DRY 原则(不要重复自己)。
IE。复制并粘贴这些查询,更改为存档表并将它们合并。

但是 Lesson_id 的列表相当长。
可能最好将它们放入临时表中,以便可以重用。

SELECT t1.*, t6.*
FROM (
    SELECT 'current' as Src,
     COUNT(DISTINCT up.lesson_id) AS assessment_count, 
     MIN(up.date) AS first_date, 
     MAX(up.date) AS last_date
    FROM cdu_user_progress up
    INNER JOIN temp_lessonid_list lst
      ON lst.lesson_id = up.lesson_id
    WHERE up.game_id = 0 
    AND up.uid = 150 
    AND up.score > -1

    UNION ALL

    SELECT 'archive' as Src,
     COUNT(DISTINCT up.lesson_id) AS assessment_count, 
     MIN(up.date) AS first_date, 
     MAX(up.date) AS last_date
    FROM cdu_user_progress_archive up
    INNER JOIN temp_lessonid_list lst
      ON lst.lesson_id = up.lesson_id
    WHERE up.game_id = 0 
    AND up.uid = 150 
    AND up.score > -1
) t1
INNER JOIN 
(
    SELECT 'current' as Src,
     AVG(c1.score) AS avg_first_scores, 
     SUM(c1.score) AS sum_first_scores
    FROM cdu_user_progress c1
    INNER JOIN temp_lessonid_list lst
      ON lst.lesson_id = c1.lesson_id
    LEFT JOIN cdu_user_progress c2 
      ON (c1.uid = c2.uid AND c1.lesson_id = c2.lesson_id AND c1.game_id = c2.game_id AND c1.level = c2.level AND c1.date > c2.date AND c2.score > -1)
    WHERE c1.game_id = 0
       AND c1.uid = 150
       AND c1.score > -1
       AND c2.date IS ''

    UNION ALL

    SELECT 'archive' as Src,
     AVG(c1.score) AS avg_first_scores, 
     SUM(c1.score) AS sum_first_scores
    FROM cdu_user_progress_archive c1
    INNER JOIN temp_lessonid_list lst
      ON lst.lesson_id = c1.lesson_id
    LEFT JOIN cdu_user_progress_archive c2 
      ON (c1.uid = c2.uid AND c1.lesson_id = c2.lesson_id AND c1.game_id = c2.game_id AND c1.level = c2.level AND c1.date > c2.date AND c2.score > -1)
    WHERE c1.game_id = 0
       AND c1.uid = 150
       AND c1.score > -1
       AND c2.date IS ''
) t6 ON t6.Src = t1.Src;

您还可以研究表分区。

关于mysql - 立即从表 AND 'archive' 表中选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58919440/

相关文章:

python - PeeWee 整数主键需要force_insert=True

php - Insert Ignore - 有没有办法知道语句是否被忽略?数据库

sql - 在 PostgreSQL 12 上按 id(唯一)分组的一个查询中同时获取房间成员、房间所有者和管理员

查询满足条件后3天内的记录的sql

外网连接MYSQL

sql - 删除除最新记录之外的所有记录?

php - 如何在相同的id但不同的列值下插入值?

mysql - 选择任何字段中包含字符串大小写的所有行

mysql - 查询重新索引 MySQL 数据库的主键

php - 使用一张表将不同的 MIME 类型上传到数据库