将所有重复引用更改为对 MAX(id) 的引用
Change all dup-references to references to MAX(id)
这是一个关于sqlite的问题。
customers (id INTEGER PRIMARY KEY, name TEXT)
orders (id INTEGER PRIMARY KEY, cid INTEGER)
我想从 customers
中删除所有重复条目(保留 MAX(id) 条目)。但在此之前,我想将 orders
中的所有引用更改为相应的 MAX(id) 值。
这是我认为正确的做法:
UPDATE orders
SET cid = (SELECT MAX(c.id)
FROM customers c
JOIN (SELECT name, id
FROM customers
WHERE id = orders.cid) q
ON c.name = q.name
GROUP BY c.name);
DELETE FROM customers
WHERE id NOT IN (SELECT MAX(id)
FROM customers
GROUP BY name);
但尤其是第一个查询已经非常慢,已经有大约 10,000 个客户。有更快的方法吗?
一些数字:我们有 120,000 名客户,其中 appx。 30,000 有 COUNT(*) > 1(当 GROUP BY 名称时)。除此之外,我们还有 200,000 个订单。完成上述查询需要将近20分钟。
使用临时 table 的 ID 可能会获得更好的性能。据我了解,SQLite 在处理此查询时遇到问题,因为在每次更新和删除时,客户都会发生变化。请注意,这种方法最适合事务。
BEGIN Transaction;
创建 Temp Table TempCustomers 作为 SELECT id,MAX(id) 作为 MaxId
来自客户
按名称分组;
CREATE TEMP TABLE TempCustomers AS
SELECT k.id, q.MaxId
FROM customers k JOIN
(SELECT MAX(d.id) as MaxId, d.name FROM customers d GROUP BY d.name)
q ON q.name = k.name;
UPDATE orders
SET cid = (SELECT MaxId
FROM TempCustomers c
WHERE id = orders.cid);
DELETE FROM customers
WHERE id NOT IN (SELECT MaxId
FROM TempCustomers);
COMMIT;
当您断开连接时,您的 Temp table 将从内存中删除。或者,如果你想保持连接而不占用内存,你可以使用 DROP Temp Table
。
编辑:在评论中提出的最终方法。
首先,为orders.cid添加一个索引。然后使用主键创建临时 table,并将 id 交换插入其中(而不是即时创建)。最后,执行清理。
BEGIN Transaction;
CREATE TEMP TABLE TempCustomers
(Id Integer PRIMARY KEY,
MaxId Integer);
INSERT INTO TempCustomers SELECT k.id, q.MaxId
FROM customers k JOIN
(SELECT MAX(d.id) as MaxId, d.name FROM customers d GROUP BY d.name)
q ON q.name = k.name;
UPDATE orders
SET cid = (SELECT MaxId
FROM TempCustomers c
WHERE id = orders.cid);
DELETE FROM customers
WHERE id NOT IN (SELECT MaxId
FROM TempCustomers);
DROP TABLE TempCustomers;
COMMIT;
这是一个关于sqlite的问题。
customers (id INTEGER PRIMARY KEY, name TEXT)
orders (id INTEGER PRIMARY KEY, cid INTEGER)
我想从 customers
中删除所有重复条目(保留 MAX(id) 条目)。但在此之前,我想将 orders
中的所有引用更改为相应的 MAX(id) 值。
这是我认为正确的做法:
UPDATE orders
SET cid = (SELECT MAX(c.id)
FROM customers c
JOIN (SELECT name, id
FROM customers
WHERE id = orders.cid) q
ON c.name = q.name
GROUP BY c.name);
DELETE FROM customers
WHERE id NOT IN (SELECT MAX(id)
FROM customers
GROUP BY name);
但尤其是第一个查询已经非常慢,已经有大约 10,000 个客户。有更快的方法吗?
一些数字:我们有 120,000 名客户,其中 appx。 30,000 有 COUNT(*) > 1(当 GROUP BY 名称时)。除此之外,我们还有 200,000 个订单。完成上述查询需要将近20分钟。
使用临时 table 的 ID 可能会获得更好的性能。据我了解,SQLite 在处理此查询时遇到问题,因为在每次更新和删除时,客户都会发生变化。请注意,这种方法最适合事务。
BEGIN Transaction;
创建 Temp Table TempCustomers 作为 SELECT id,MAX(id) 作为 MaxId
来自客户
按名称分组;
CREATE TEMP TABLE TempCustomers AS
SELECT k.id, q.MaxId
FROM customers k JOIN
(SELECT MAX(d.id) as MaxId, d.name FROM customers d GROUP BY d.name)
q ON q.name = k.name;
UPDATE orders
SET cid = (SELECT MaxId
FROM TempCustomers c
WHERE id = orders.cid);
DELETE FROM customers
WHERE id NOT IN (SELECT MaxId
FROM TempCustomers);
COMMIT;
当您断开连接时,您的 Temp table 将从内存中删除。或者,如果你想保持连接而不占用内存,你可以使用 DROP Temp Table
。
编辑:在评论中提出的最终方法。
首先,为orders.cid添加一个索引。然后使用主键创建临时 table,并将 id 交换插入其中(而不是即时创建)。最后,执行清理。
BEGIN Transaction;
CREATE TEMP TABLE TempCustomers
(Id Integer PRIMARY KEY,
MaxId Integer);
INSERT INTO TempCustomers SELECT k.id, q.MaxId
FROM customers k JOIN
(SELECT MAX(d.id) as MaxId, d.name FROM customers d GROUP BY d.name)
q ON q.name = k.name;
UPDATE orders
SET cid = (SELECT MaxId
FROM TempCustomers c
WHERE id = orders.cid);
DELETE FROM customers
WHERE id NOT IN (SELECT MaxId
FROM TempCustomers);
DROP TABLE TempCustomers;
COMMIT;