【问题标题】:DELETE FROM optimization从优化中删除
【发布时间】:2011-06-23 04:25:54
【问题描述】:

我有这个查询:

从 f 中删除
      哪里英尺!='f'
         或 fs 不在(选择 fs
                           从 f
                       按 fs 分组
                         有 COUNT(fs) >1)

它的工作做得很好,只是它比我预期的要花更多的时间。我说的是 2.25 秒将 ~209,000 条记录减少到 ~187,000 条。我认为它可以改进,我想知道如何。

查询解释:

addr 操作码 p1 p2 p3 p4 p5 注释
---- ------------- ---- ---- ---- ----- -- -- ------------
0 轨迹 0 0 0 00
1 转到 0 82 0 00
2 空 0 1 0 00
3 字符串 8 0 3 0 f 00
4 打开读取 0 2 0 4 00
5 倒带 0 69 0 00
6 列 0 2 4 00
7 Ne 3 66 4 collseq(BINARY) 63
8 如果 7 53 0 00
9 整数 1 7 0 00
10 空 0 6 0 00
11 OpenEphemeral 4 1 0 keyinfo(1,BINARY) 00
12 OpenEphemeral 5 2 0 keyinfo(1,BINARY) 00
13 整数 0 11 0 00
14 整数 0 10 0 00
15 戈苏 13 50 0 00
16 打开读取 2 2 0 4 00
17 倒带 2 23 0 00
18 栏 2 3 16 00
19 序列 5 17 0 00
20 制作记录 16 2 4 00
21 IDx插入 5 4 0 00
22 下一个 2 18 0 01
23 关闭 2 0 0 00
24 排序 5 53 0 00
25 列 5 0 15 00
26 比较 14 15 1 keyinfo(1,BINARY) 00
27 跳 28 32 28 00
28 移动 15 14 1 00
29 戈苏 12 41 0 00
30 IfPos 11 53 0 00
31 戈苏 13 50 0 00
32 列 5 0 16 00
33 AggStep 0 16 9 计数(1) 01
34 列 5 0 8 00
35 整数 1 10 0 00
36 下一个 5 25 0 00
37 戈苏 12 41 0 00
38 转到 0 53 0 00
39 整数 1 11 0 00
40 返回 12 0 0 00
41 IfPos 10 43 0 00
42 返回 12 0 0 00
43 AggFinal 9 1 0 计数(1) 00
44 整数 1 4 0 00
45 勒 4 42 9 6a
46 复印 8 18 0 00
47 制作记录 18 1 4 c 00
48 Idx插入 4 4 0 00
49 返回 12 0 0 00
50 空 0 8 0 00
51 空 0 9 0 00
52 返回 13 0 0 00
53 列 0 3 4 00
54 非空 4 57 0 00
55 倒带 4 66 0 00
56 转到 0 68 0 00
57 亲和力 4 1 0 c 00
58 找到 4 65 4 1 00
59 非空 6 63 0 00
60 找到 4 62 6 1 00
61 整数 -1 6 0 00
62 AddImm 6 1 0 00
63 如果 6 68 0 00
64 转到 0 66 0 00
65 转到 0 68 0 00
66 行 0 2 0 00
67 行集添加 1 2 0 00
68 下一个 0 6 0 01
69 关闭 0 0 0 00
70 开放写入 0 2 0 4 00
71 OpenWrite 1 3 0 密钥信息(1,BINARY) 00
72 行集读取 1 79 2 00
73 不存在 0 78 2 00
74 行 0 20 0 00
75 列 0 1 19 00
76 IDx删除 1 19 2 00
77 删除 0 1 0 f 00
78 转到 0 72 0 00
79 关闭 1 3 0 00
80 关闭 0 0 0 00
81 暂停 0 0 0 00
82 交易 0 1 0 00
83 验证Cookie 0 2 0 00
84 桌锁 0 2 1 f 00
85 转到 0 2 0 00 

表定义(还没有索引):

创建表 f (fi 整数主键自动增量,
                fn 字符串,
                英尺字符串,
                fs 整数)

【问题讨论】:

  • 表定义?定义的索引?不完整的问题得到不完整的答案。
  • 对不起,我忘了。我已经编辑了这个问题。 :)
  • 另一件值得研究的是查询的解释,因此查询优化器会告诉您它对查询的作用。如果它做了一些已经非常聪明和快速的事情,那么没有理由进一步优化。
  • 而不是ft != 'f',你能像ft in ('x', 'b')那样积极地表达谓词吗?我想它可以帮助索引。

标签: sql optimization sqlite sql-delete


【解决方案1】:

我不确定两秒是否是“杀手级”查询(当然,这取决于您的情况和需要),但您可以测试的一件事是拆分查询成两个。

这是因为它当前会删除符合任一条件的记录,因此可以轻松转换为两个 delete 语句(如果您想确保它是原子的,则在事务中)。你可以试试:

DELETE FROM f WHERE ft != 'f';
DELETE FROM f WHERE fs NOT IN (
    SELECT fs FROM f
    GROUP BY fs
    HAVING COUNT(fs) >1);

看看这是否会有所改善。它可能会也可能不会,这取决于您的 DBMS 和数据的构成。在最有可能更快的第一个查询中,它可能会删除交叉记录(满足这两个条件的记录)。

但是,与所有数据库优化一样,衡量,不要猜测!

然后您可以重新组合并重新评估,或者如果仍然存在问题,则可以集中精力加快第二个更简单的查询。

需要特别确保的一件事:在ftfs 列上都有索引。如果您还没有查询,这应该会大大加快您的查询速度。

【讨论】:

  • 这些索引做得很好:它们将查询时间减少了 50%。 :) 另一方面,查询拆分在索引优化后引入了 10% 的延迟——在这种情况下,SQLite 可能已经足够优化。我相信索引增益现在查询时间变得可以接受了。谢谢你的提示! :)
【解决方案2】:

试试这个查询

DELETE FROM f
WHERE ft <> 'f'
   OR NOT EXISTS (Select * from f f2
       WHERE f2.fs=f.fs and f2.id <> f.id)

索引

on ft ; single-column
on (fs, id) ; composite, in that order

【讨论】:

  • 这样查询时间减少了三分之一,还不错。但是,单个索引将其减少了一半,这甚至更好。 :) 无论如何感谢您的提示,学习做同一件事的不同方法总是好的。 ;)
【解决方案3】:
DELETE f
FROM (
      SELECT fs 
      FROM f     
      GROUP BY fs     
      HAVING COUNT(fs) <=1
     ) s
WHERE (f.ft != 'f' OR f.fs = s.fs)

【讨论】:

  • Ermm,这种语法DELETE FROM (...) 显然不被 SQLite 支持。 :(但无论如何,谢谢老兄,这也是一个很好的答案。:)
猜你喜欢
  • 1970-01-01
  • 2016-10-25
  • 2022-10-29
  • 2016-10-06
  • 2011-11-15
  • 1970-01-01
  • 1970-01-01
  • 2021-08-31
  • 2014-01-09
相关资源
最近更新 更多