将所有重复引用更改为对MAX的引用(id)

时间:2015-02-16 12:39:01

标签: sqlite

这是关于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分钟。

1 个答案:

答案 0 :(得分:1)

使用临时ID表可以获得更好的性能。据我了解,SQLite在查询时遇到问题,因为每次更新和删除时,客户都会更改。请注意,此方法最适合在事务中使用。

BEGIN Transaction;

<击>     CREATE Temp Table TempCustomers作为SELECT id,MAX(id)为MaxId            来自客户            GROUP BY名称;

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表将从内存中删除。或者,如果您想保持连接而不是占用内存,则可以使用DROP Temp Table

编辑:最终方法建议在评论中发展。

首先,向orders.cid添加索引。然后使用主键创建临时表,并将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;