gpt4 book ai didi

SQL 魔法 - 查询不应该花费 15 个小时,但确实如此

转载 作者:IT王子 更新时间:2023-10-29 00:34:53 25 4
gpt4 key购买 nike

好的,所以我有一个非常可怕的 MySQL 表(90 万条记录,总共 180 MB),我想从具有更高 date_updated 的子组记录中提取并计算每个组的加权平均值。计算运行了大约 15 个小时,我有一种强烈的感觉,我做错了

首先,巨大的 table 布局:

  • 类别
  • element_id
  • date_updated
  • 重量
  • source_prefix
  • source_name

这里唯一的关键是 element_id(BTREE,~8k 唯一元素)。

及计算过程:

为每个组和子组制作哈希。

CREATE TEMPORARY TABLE `temp1` (INDEX ( `ds_hash` ))
SELECT `category`,
`element_id`,
`source_prefix`,
`source_name`,
`date_updated`,
`value`,
`weight`,
MD5(CONCAT(`category`, `element_id`, `source_prefix`, `source_name`)) AS `subcat_hash`,
MD5(CONCAT(`category`, `element_id`, `date_updated`)) AS `cat_hash`
FROM `bigbigtable` WHERE `date_updated` <= '2009-04-28'

我真的不明白这种对哈希的大惊小怪,但这种方式工作得更快。我猜是黑魔法。

查找每个子组的最大日期

CREATE TEMPORARY TABLE `temp2` (INDEX ( `subcat_hash` ))

SELECT MAX(`date_updated`) AS `maxdate` , `subcat_hash`
FROM `temp1`
GROUP BY `subcat_hash`;

将 temp1 与 temp2 连接起来以找到类别的加权平均值

CREATE TEMPORARY TABLE `valuebycats` (INDEX ( `category` ))
SELECT `temp1`.`element_id`,
`temp1`.`category`,
`temp1`.`source_prefix`,
`temp1`.`source_name`,
`temp1`.`date_updated`,
AVG(`temp1`.`value`) AS `avg_value`,
SUM(`temp1`.`value` * `temp1`.`weight`) / SUM(`weight`) AS `rating`

FROM `temp1` LEFT JOIN `temp2` ON `temp1`.`subcat_hash` = `temp2`.`subcat_hash`
WHERE `temp2`.`subcat_hash` = `temp1`.`subcat_hash`
AND `temp1`.`date_updated` = `temp2`.`maxdate`

GROUP BY `temp1`.`cat_hash`;

(现在我浏览并写下了所有内容,在我看来,我应该在最后一个查询中使用 INNER JOIN(以避免 900k*900k 临时表)。

不过,有没有正常的方法可以做到这一点?

UPD:一些图片供引用:

删除了无效的 ImageShack 链接

UPD:解释建议的解决方案:

+----+-------------+-------+------+---------------+------------+---------+--------------------------------------------------------------------------------------+--------+----------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------+---------------+------------+---------+--------------------------------------------------------------------------------------+--------+----------+----------------------------------------------+
| 1 | SIMPLE | cur | ALL | NULL | NULL | NULL | NULL | 893085 | 100.00 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | next | ref | prefix | prefix | 1074 | bigbigtable.cur.source_prefix,bigbigtable.cur.source_name,bigbigtable.cur.element_id | 1 | 100.00 | Using where |
+----+-------------+-------+------+---------------+------------+---------+--------------------------------------------------------------------------------------+--------+----------+----------------------------------------------+

最佳答案

使用散列是数据库引擎执行连接的方式之一。您必须自己编写基于散列的连接的情况应该很少见;这看起来肯定不像其中之一,它有一个包含一些聚合的 90 万行表。

根据您的评论,此查询可能会满足您的要求:

SELECT cur.source_prefix, 
cur.source_name,
cur.category,
cur.element_id,
MAX(cur.date_updated) AS DateUpdated,
AVG(cur.value) AS AvgValue,
SUM(cur.value * cur.weight) / SUM(cur.weight) AS Rating
FROM eev0 cur
LEFT JOIN eev0 next
ON next.date_updated < '2009-05-01'
AND next.source_prefix = cur.source_prefix
AND next.source_name = cur.source_name
AND next.element_id = cur.element_id
AND next.date_updated > cur.date_updated
WHERE cur.date_updated < '2009-05-01'
AND next.category IS NULL
GROUP BY cur.source_prefix, cur.source_name,
cur.category, cur.element_id

GROUP BY 按来源+类别+元素执行计算。

JOIN 用于过滤掉旧条目。它查找后面的条目,然后 WHERE 语句过滤掉存在后面条目的行。像这样的连接受益于 (source_prefix, source_name, element_id, date_updated) 上的索引。

有很多方法可以过滤掉旧条目,但这个方法往往表现得相当好。

关于SQL 魔法 - 查询不应该花费 15 个小时,但确实如此,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/897185/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com