COUNT(DISTINCT) 的百分位数与相关 WHERE 仅适用于视图(或没有 DISTINCT)

Posted

技术标签:

【中文标题】COUNT(DISTINCT) 的百分位数与相关 WHERE 仅适用于视图(或没有 DISTINCT)【英文标题】:percentile by COUNT(DISTINCT) with correlated WHERE only works with a view (or without DISTINCT) 【发布时间】:2012-12-31 05:12:44 【问题描述】:

我有一个奇怪的问题,我不知道这是我的语法(看起来很简单)还是错误(或者只是不受支持)。

这是我的查询有效但不必要的慢:

UPDATE table1 
    SET table1column1 = 
        (SELECT COUNT(DISTINCT table2column1) FROM table2view WHERE table2column1 <= (SELECT table2column1 FROM table2 WHERE table2.id = table1.id) )
        / 
        (SELECT COUNT(DISTINCT table2column1) FROM table2) 

       + (SELECT COUNT(DISTINCT table2column2) FROM table2view WHERE table2column2 <= (SELECT table2column2 FROM table2 WHERE table2.id = table1.id) ) 
        / 
        (SELECT COUNT(DISTINCT table2column2) FROM table2) 

       + (SELECT COUNT(DISTINCT table2column3) FROM table2view WHERE table2column3 <= (SELECT table2column3 FROM table2 WHERE table2.id = table1.id) ) 
        / (SELECT COUNT(DISTINCT table2column3) FROM table2);

这只是删除重复项后三个百分位数(table2column1、table2column2 和 table2column3)的总和。

这就是奇怪的地方。我必须为此使用一个视图来处理带有WHERE 的子查询,否则它只会UPDATE 的第一行table1,并将其余行的table1column1 设置为0table2viewtable2 完全相同。是的,很奇怪。

如果我不使用DISTINCT,我可以在没有视图的情况下使用。那有意义吗? 注意:我必须有DISTINCT,因为我有很多重复项。

我尝试仅从视图中将其设为SELECT,但这反而减慢了速度。

有谁知道问题出在哪里,以及重新处理此查询的最佳方法,以便不需要很长时间?它在TRIGGER 中,而且更新的数据非常按需提供。

非常感谢!

详情

我正在phpMyAdmin的命令行中测试速度。

我很确定降级来自视图,因为视图越多,我使用的实际表越少,它变得越慢。

当我在没有DISTINCT 的情况下进行操作时,速度快如闪电。

仅适用于视图?

好的,所以我只是设置了table2 的副本。我首先尝试执行原始查询,用副本替换视图。不行。

我尝试使用副本而不是视图来执行以下查询。不行。

希望这些常量的引入能更好地展示我正在尝试做的事情。

SET @table2column1_distinct_count = (SELECT COUNT(DISTINCT table2column1) FROM table2);
SET @table2column2_distinct_count = (SELECT COUNT(DISTINCT table2column2) FROM table2);
SET @table2column3_distinct_count = (SELECT COUNT(DISTINCT table2column3) FROM table2);
UPDATE table1, table2
    SET table1.table1column1 = (SELECT COUNT(DISTINCT table2column1) FROM  table2view WHERE table2column1 <= table2.table2column1) / @table2column1_distinct_count 
    + (SELECT COUNT(DISTINCT table2column2) FROM  table2view WHERE table2column2 <= table2.table2column2) / @table2column2_distinct_count 
    + (SELECT COUNT(DISTINCT table2column3) FROM  table2view WHERE table2column3 <= table2.table2column3) / @table2column3_distinct_count 
        WHERE table1.id = table2.id;

同样,当我使用table2 而不是table2view 时,它只会正确更新第一行并设置所有其他行的table1.table1column1 = 0

数学

我试图通过idtable1.table1column1 = 设置为table2column1table2column2table2column3 的百分位数之和。

我通过(计算 table2columnX table2columnX 的不同值)/(不同 table2columnXs 的总计数)来计算百分位数。

我使用DISTINCT 去除过多的重复。

查看

这是视图的SELECT。这有帮助吗?

CREATE VIEW myTable.table2view AS SELECT
    table2.table2column1 AS table2column1,
    table2.table2column2 AS table2column2,
    table2.table2column2 AS table2column3,
FROM table2
GROUP BY table2.id;

视图的SELECT 中的GROUP BY 有什么特别之处可以使这项工作(我没有看到)吗?

【问题讨论】:

你能提供你想要更新列的值的执行计划吗?没有它,很难真正弄清楚发生了什么。 @Xnoise 感谢您的关注!一旦我弄清楚那是什么,我会尽快回复你。大声笑现在,我倾向于使用“临时表”,直到COUNT(DISTINCT) 允许相关子查询(我业余猜测是问题所在):***.com/a/1615371/1382306 【参考方案1】:

我可能会说查询很慢,因为它在触发器触发时重复访问表。

我不是 SQL 专家,但我尝试使用临时表来组合查询。您可以查看它是否有助于加快查询速度。我在下面的代码示例中使用了不同但相似的列名。

编辑:我之前的代码中有一个计算错误。现已更新。

SELECT COUNT(id) INTO @no_of_attempts from tb2;

-- DROP TABLE IF EXISTS S1Percentiles;
-- DROP TABLE IF EXISTS S2Percentiles;
-- DROP TABLE IF EXISTS S3Percentiles;

CREATE TEMPORARY TABLE S1Percentiles (
    s1 FLOAT NOT NULL,
    percentile FLOAT NOT NULL DEFAULT 0.00
);

CREATE TEMPORARY TABLE S2Percentiles (
    s2 FLOAT NOT NULL,
    percentile FLOAT NOT NULL DEFAULT 0.00
);

CREATE TEMPORARY TABLE S3Percentiles (
    s3 FLOAT NOT NULL,
    percentile FLOAT NOT NULL DEFAULT 0.00
);



INSERT INTO S1Percentiles (s1, percentile)
    SELECT A.s1, ((COUNT(B.s1)/@no_of_attempts)*100)
    FROM (SELECT DISTINCT s1 from tb2) A
    INNER JOIN tb2 B
    ON B.s1 <= A.s1
    GROUP BY A.s1;

INSERT INTO S2Percentiles (s2, percentile)
    SELECT A.s2, ((COUNT(B.s2)/@no_of_attempts)*100)
    FROM (SELECT DISTINCT s2 from tb2) A
    INNER JOIN tb2 B
    ON B.s2 <= A.s2
    GROUP BY A.s2;

INSERT INTO S3Percentiles (s3, percentile)
    SELECT A.s3, ((COUNT(B.s3)/@no_of_attempts)*100)
    FROM (SELECT DISTINCT s3 from tb2) A
    INNER JOIN tb2 B
    ON B.s3 <= A.s3
    GROUP BY A.s3;

-- select * from S1Percentiles;
-- select * from S2Percentiles;
-- select * from S3Percentiles;

UPDATE tb1 A
    INNER JOIN
    (
    SELECT B.tb1_id AS id, (C.percentile + D.percentile + E.percentile) AS sum FROM tb2 B
        INNER JOIN S1Percentiles C
        ON B.s1 = C.s1
        INNER JOIN S2Percentiles D
        ON B.s2 = D.s2
        INNER JOIN S3Percentiles E
        ON B.s3 = E.s3
    ) F
    ON A.id = F.id

    SET A.sum = F.sum;

-- SELECT * FROM tb1;

DROP TABLE S1Percentiles;
DROP TABLE S2Percentiles;
DROP TABLE S3Percentiles;

它的作用是记录每个分数组的百分位数,然后最后只用必要的数据更新tb1 列,而不是重新计算每个学生行的百分位数。

您还应该索引列 s1s2s3 以优化对这些列的查询。

注意:请根据您的数据库架构更新列名。另请注意,每个百分位数计算都乘以100,因为我相信百分位数通常是这样计算的。

【讨论】:

所以最重要的是,您建议使用临时表而不是视图?有趣的是,我从未真正使用过临时表。我会遇到与视图类似的速度问题吗?当 table2 的长度变得像 1M 记录长时,这可以正常工作吗?非常感谢您的回答!

以上是关于COUNT(DISTINCT) 的百分位数与相关 WHERE 仅适用于视图(或没有 DISTINCT)的主要内容,如果未能解决你的问题,请参考以下文章

按百分位数将类似 sql 的查询的结果分组:在 Redshift / postgresql

大熊猫是否表现出错误的百分位数?

[MongoDB]count,gourp,distinct

如何计算百分位数与Python / numpy的

distinct与NULL在count的注意事项

mongo中的高级查询之聚合操作(distinct,count,group)与数据去重