【问题标题】:SQLite trigger optimizationSQLite 触发器优化
【发布时间】:2011-11-13 02:33:31
【问题描述】:

这是基于this question about query optimization的后续。

按照建议,为了快速选择,我尝试在插入时使用触发器预先计算一些数据。

基本上,我想将给定列值的出现次数保留到给定表中。

以下架构用于存储每个值的出现次数:

CREATE TABLE valuecount (value text, count int)
CREATE INDEX countidx ON t (count DESC)
CREATE UNIQUE INDEX valueidx ON valuecount (value);

这是我一直在测试的触发器:

CREATE TRIGGER counttrigger INSERT ON collection
  FOR EACH ROW
    BEGIN
      INSERT OR REPLACE INTO valuecount VALUES 
      (NEW.value, coalesce((SELECT count + 1 FROM count WHERE valuecount.query LIKE 
       NEW.value), 1));
    END;

collection 表上的典型插入包含几十万行,在单个 INSERT INTO ... SELECT ... 语句中(我正在将数据从一个数据库合并到另一个数据库)。

问题在于,使用此触发器,插入 300K 行需要 4 小时,而不是 300 毫秒 ...

有没有办法在不牺牲性能的情况下实现这一目标?

提前感谢您的帮助,

【问题讨论】:

  • 您可能想尝试在 NEW 中加入更新,然后在不存在行的情况下插入 SELECT FROM NEW。
  • 你能举个例子吗?
  • 抱歉,我不知道At this time SQLite supports only FOR EACH ROW triggers, not FOR EACH STATEMENT triggers.。在我使用的其他数据库中,它们在FOR EACH STATEMENT 范围内运行,您可以在其中对正在更改的整个数据集进行操作。我不知道 SQLite 的这种限制,所以你不能像我在之前的评论中所说的那样去做。

标签: sql sqlite optimization triggers query-optimization


【解决方案1】:

由于从一个数据库导入到另一个数据库不像其他插入那样常见,您能否将触发器提供的逻辑推迟到导入完成?查看触发器的性质,您似乎可以在导入所有数据后为每种查询类型执行一次 COUNT。总体而言,这将大大减少查询次数。

如果这不可能,有没有办法避免使用 LIKE?此操作比直接比较更昂贵。

【讨论】:

  • 我目前正在尝试在插入之前执行 COUNT(仅在 300K 行上),并立即插入新计数。合并后无法在整个数据库上完成 COUNT,因为它花费了太多时间(即使有数亿行也需要快速)。
【解决方案2】:

好吧,看来使用触发器毕竟不是一个好主意。

由于我要合并来自不同数据库的表,因此我在插入之前根据要合并的表的内容将 upsert 插入到 valuecount 表中,全部在一个语句中。

所以我没有触发器,而是有一个看起来像这样的查询,在我的 INSERT INTO ... SELECT ... 语句之前执行:

INSERT OR REPLACE INTO valuecount
SELECT value, coalesce((SELECT count FROM valuecount WHERE valuecount.value = collection.value) + COUNT(value), COUNT(value))
FROM attached.collection GROUP BY value

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多