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
设置为0
。 table2view
与 table2
完全相同。是的,很奇怪。
如果我不使用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
。
数学
我试图通过id
将table1.table1column1
= 设置为table2column1
、table2column2
和table2column3
的百分位数之和。
我通过(计算 table2columnX
table2columnX 的不同值)/(不同 table2columnX
s 的总计数)来计算百分位数。
我使用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
列,而不是重新计算每个学生行的百分位数。
您还应该索引列 s1
、s2
和 s3
以优化对这些列的查询。
注意:请根据您的数据库架构更新列名。另请注意,每个百分位数计算都乘以100
,因为我相信百分位数通常是这样计算的。
【讨论】:
所以最重要的是,您建议使用临时表而不是视图?有趣的是,我从未真正使用过临时表。我会遇到与视图类似的速度问题吗?当 table2 的长度变得像 1M 记录长时,这可以正常工作吗?非常感谢您的回答!以上是关于COUNT(DISTINCT) 的百分位数与相关 WHERE 仅适用于视图(或没有 DISTINCT)的主要内容,如果未能解决你的问题,请参考以下文章