我需要在一个表中更新大量记录(大约300k到500k)并在另一个表中删除数百万个记录。由于这需要一些时间,我使用LIMIT在块中执行此操作,因此我可以向用户显示进度条。
我的第一个小问题是,为什么我可以在SQLiteSpy中使用以下语句,但在使用ADO.NET提供程序System.Data.SQLite时却不能使用?
UPDATE Table1
SET Status1 = newValue1, Status2 = value2
WHERE Key1 = key1Value
AND Status1 = value1
LIMIT 1000
我必须使用以下语句才能使其正常工作:
UPDATE Table1
SET Status1 = newValue1, Status2 = value2
WHERE Key1 = key1Value
AND Key2 in (
SELECT Key2
FROM Table
WHERE Key1 = key1Value
AND Status1 = value1
LIMIT 1000)
我使用的是最新版本的SQLiteSpy(使用SQLite 3.7.2)和System.Data.SQlite。
我的另一个问题更复杂。 我正在使用2个表:
CREATE TABLE Table1 (
Key1 INTEGER NOT NULL,
Key2 INTEGER NOT NULL,
...
Some fixed varchar data fields
...
Status1 CHAR(1) NOT NULL,
Status2 VARCHAR NULL,
Status3 CHAR(1) NOT NULL,
UpdateDate DATETIME NOT NULL,
CONSTRAINT PK_Table1 PRIMARY KEY (Key1 ASC, Key2 ASC))
和
CREATE TABLE Table2 (
Key1 INTEGER NOT NULL,
Key2 INTEGER NOT NULL,
Key3 INTEGER NOT NULL,
...
Some fixed varchar data fields
...
CONSTRAINT PK_Table2 PRIMARY KEY (Key1 ASC, Key2 ASC, Key3 ASC))
on table1有两个索引:
CREATE INDEX IDX_Tabel1_Status1 ON Table1 (Key1 ASC, Status1 ASC, Key2 ASC)
CREATE INDEX IDX_Tabel1_Status2 ON Table1 (Key1 ASC, Status2 ASC, Key2 ASC)
正如您可能已经猜到的那样,两个表中的Key1和Key2都很受欢迎。
我想要做的是,在Table2中删除Table1中具有特定状态的记录的所有记录,并将3个状态字段重置为其原始值并更新Table1中的日期。由于涉及的记录数量可能很大(表1包含多达500k记录,而表2包含20M到40M之间),并且大部分时间它涉及table1的50%到100%之间,我在“小”中执行删除和更新块(表1中的1000到10000条记录之间)。所以我重复以下两个语句,直到删除/更新所有相关记录(每个事务删除和更新一次):
DELETE FROM Table2
WHERE Key1 = @Key1
AND Key2 in (
SELECT Key2
FROM Table
WHERE Key1 = @Key1
AND Status1 = @Status1
LIMIT 1000)
UPDATE Table1
SET Status1 = @NewStatus1, Status2 = @Status2, Status3 = @Status3, UpdateDate = @Date
WHERE Key1 = @Key1
AND Key2 in (
SELECT Key2
FROM Table
WHERE Key1 = @Key1
AND Status1 = @Status1
LIMIT 1000)
删除速度非常快,但更新需要花费大量时间(1000条记录大约需要2到3秒)。我想这是因为两个索引都需要更新。所以我想知道在删除/更新之前是否会提高性能以丢弃两个索引并在之后重新创建它们。但随后子选择会变慢。在什么时候(涉及的总记录的百分比,或记录的绝对数量),我应该考虑删除索引吗?
谢谢, 马克
答案 0 :(得分:0)
在什么时候(涉及的总记录的百分比,或记录的绝对数量),我应该考虑删除索引吗?
我无法分辨,但是如果有大量的数据,那么在交易完成后,删除索引并在以后重新创建它们的效果大都会带来好处。
获得良好答案的唯一方法是根据实际情况衡量绩效。
恕我直言,你的主要问题是向用户显示进度的限制条款。我不会这样做。如果省略,它可以产生显着的性能奖励。此外,如果我是一名用户,我宁愿尽快完成工作,也不要知道进度。 您可以使用选取框显示正在进行的操作。
您还可以测量每条记录的平均时间(或公式,具体取决于数据量),并显示有关进度的有根据的猜测。每次运行测量,将其保存在某处并从最近10次运行中建立平均值以计算进度。
或者您可以将逻辑分成不同的步骤,并显示当前正在执行的查询的步骤编号。
如果确实需要显示进度,请尝试使用and exists语句而不是in子句。它可能会更快。