我希望找到一种从我的数据库中删除重复记录的有效方法。首先,我使用了一个使用连接等的存储过程,这导致查询执行速度非常慢。现在,我正在尝试一种不同的方法。请考虑以下问题:
/* QUERY A */
SELECT *
FROM my_table
WHERE col1 = value
AND col2 = value
AND col3 = value
此查询仅在12秒内执行,结果为182.400条记录。表中的行数目前为420.930.407,并且col1和col3已编入索引。
下一个查询:
/* QUERY B */
WITH ALL_RECORDS AS
(SELECT id
FROM my_table
WHERE col1 = value
AND col2 = value
AND col3 = value)
SELECT *
FROM ALL_RECORDS
这个查询花了不到2秒的时间,并给出了表中182.400条记录的所有id(根据where子句)。
然后,我的上一个查询是一个查询,它选择在我要分组的列上分组的所有记录的最低(第一个)ID,以检查重复项:
/* QUERY C */
SELECT MIN(id)
FROM my_table
WHERE col1 = value
AND col2 = value
AND col3 = value
GROUP BY col1,
col2,
col3,
col4,
col5,
col6
同样,此查询在不到2秒的时间内执行。结果是30.400,这意味着182.400条记录中有30.400条唯一记录是唯一的。
现在,我想删除(或者,首先选择以确保我的查询正确)所有非独特的记录。所以,我想从my_table中删除182.400 - 30.400 = 152.000条记录。
我以为我将最后两个查询合并:根据col1,col2和col3(查询B)上的where子句获取属于我的数据集的所有id,然后删除/全选来自该数据集的记录,其id不在唯一记录ID的id列表中(查询C)。
然而,当我从查询B中选择所有查询B.id NOT IN查询C时,查询不需要2,4或12(14或16)秒,但似乎需要永远(在1之后显示20.000条记录)分钟,2分钟后大约40.000,所以我取消了查询,因为它会找到152.000条记录,这将花费8分钟这样)。
WITH ALL_RECORDS AS
(SELECT id
FROM my_table
WHERE col1 = value
AND col2 = value
AND col3 = value)
SELECT id
FROM ALL_RECORDS
WHERE id NOT IN
(SELECT MIN(id)
FROM my_table
WHERE col1 = value
AND col2 = value
AND col3 = value
GROUP BY col1,
col2,
col3,
col4,
col5,
col6)
我知道NOT IN
速度很慢,但我无法理解它的速度有多慢(因为两个查询都不会在不到2秒的时间内执行)。
有没有人对我如何解决这个难题有一些好的建议?
------------------补充资料------------------
以前的解决方案是以下存储过程。出于某种原因,它在我的接受环境中完美地执行,但不在我的生产环境中。目前,我们有超过4亿条生产记录和200多万条接受记录,所以这可能是一个原因。
DELETE my_table
FROM my_table
LEFT OUTER JOIN
(SELECT MIN(id) AS RowId,
col1,
col2,
col3,
col4,
col5,
col6
FROM my_table
WHERE col1 = value
AND col2 = value
AND col3 = value
GROUP BY col1,
col2,
col3,
col4,
col5,
col6) AS KeepRows ON my_table.id = KeepRows.RowId
WHERE KeepRows.RowId IS NULL
AND my_table.col1 = value
AND my_table.col2 = value
AND my_table.col3 = value
我已将此解决方案基于stackoverflow上的另一个答案(目前无法找到它),但我觉得我应该能够基于在几秒钟内执行的查询B和C创建查询。 ..
答案 0 :(得分:1)
将两个2秒查询组合在一起通常不会导致单个4秒查询,因为与基础表不同,查询很少被编入索引。
此类任务的常用方法是将您要保留的id
缓存在临时表中,相应地对其进行索引,然后在left join
中使用它(或{{ 1}} - 我打赌生成的执行计划实际上是相同的。)
如果您将在主表上使用索引,则可以获得更多性能。例如,我认为not in
应该为您的代码提供一些提升(列不一定按此顺序提及,通常取决于它们的基数)。
答案 1 :(得分:1)
with dupl as (
select row_number() over(partition by col1,col2,col3,col4,col5,col6 order by id) rn,
id,col1,col2,col3,col4,col5,col6
from myTable
)
delete dupl where rn>1