【问题标题】:SQLite - Help to Make Complicated Query More EfficientSQLite - 帮助提高复杂查询的效率
【发布时间】:2014-03-13 17:35:20
【问题描述】:

数据是财务数据,以存储桶的形式结构化,其中一个存储桶 (Rollup) 可以包含其他数据存储桶。作为示例结构:

Rollup1 | Dept1
Rollup1 | Rollup2 | Dept2
Rollup1 | Rollup2 | Dept3
Rollup1 | Rollup3 | Dept4
Rollup1 | Rollup3 | Rollup4 | Dept5
Rollup1 | Rollup3 | Rollup4 | Dept6

这有 8 列,Rollups 和 Depts 分散在各处(但叶子总是单个 Depts)。大约 10k 行。

查询结果的目标是显示包含所有汇总的单列,具有可变逻辑以正常显示某些汇总,并修改所有其他汇总。

例如,如果我的变量包含“Dept4”,我的结果将是:

Rollup1
Rollup3
NA - Rollup2
NA - Rollup4

在实际场景中,有 3 个变量决定 Rollup 列的显示。

这就是我所拥有的,它应该可以发挥作用,但是性能非常糟糕。 1 Query 最多需要 5 秒,我想改进一下。

SELECT DISTINCT CASE
   WHEN "2" NOT IN
      (
         SELECT "2"
         FROM "Finance New"
         WHERE (@VAR3 = 'All' OR @VAR3 IN ("2","3","4","5","6","7","8","9"))
         AND (@VAR4 = 'All' OR "10" = @VAR4)
         AND (@VAR5 = 'All' OR "11" = @VAR5)
         )
   THEN
      'Z N/A - ' || "2"
   ELSE
      "2"
   END AS COL2
FROM "Finance New"
WHERE "5" <> 'All Applicable' AND "1" <> '9999'
AND "2" LIKE '9%'

UNION

SELECT DISTINCT CASE
   WHEN "3" NOT IN
      (
         SELECT "3"
         FROM "Finance New"
         WHERE (@VAR3 = 'All' OR @VAR3 IN ("2","3","4","5","6","7","8","9"))
         AND (@VAR4 = 'All' OR "10" = @VAR4)
         AND (@VAR5 = 'All' OR "11" = @VAR5)
         )
   THEN
      'Z N/A - ' || "3"
   ELSE
      "3"
   END AS COL2
FROM "Finance New"
WHERE "5" <> 'All Applicable' AND "1" <> '9999'
AND "3" LIKE '9%'
UNION

Etc, for each of the columns in the Rollup/Dept Tree report.

每个联合查询中的内部选择根据可变条件附加到文本。排序是自动完成的。 UNION (AND "3" LIKE "9%") 之前的最后一行是实际抓取汇总。汇总均以 9 开​​头。

输入参数被标记为@VARx。

我想知道是否有更有效的方法来执行此操作,假设我无法创建临时表并且无法更改数据的结构。

谢谢!

【问题讨论】:

  • '@COL3'应该是字符串还是参数?
  • SQL 中,字符串必须使用单引号',表/列名必须使用双引号"。 SQLite 接受其他引号以与 MySQL 兼容,但这使得该查询不可读;请修复它。
  • 这正是我正在使用的 SQLite 的实现所期望的语法。 '@VARNAME' 是实现对变量的表示。在其他情况下,单引号和双引号的使用如您所述 - 双引号指的是列名和表名,单引号表示字符串。我将把 '@VARNAME' 改为 @VARNAME 并注意这代表一个输入参数。
  • 你有索引吗?你能加点吗?列的数据类型是什么?你能改变它们吗?
  • 你有哪个 SQLite 版本?你能更新吗?

标签: sqlite performance


【解决方案1】:
  1. 所有这些 OR 都阻止使用索引。 如果可能,请删除那些 @VAR = 'All' 比较(或其他比较)并根据实际的 VAR3/4/5 值动态创建 SQL 字符串。
  2. LIKE 阻止使用索引(因为 LIKE(或 GLOB)需要索引列上的 TEXT 亲和性)。 将其替换为普通比较,即将"col" LIKE '9%' 替换为"col" &gt;= '9' AND "col" &lt; ':'
  3. UNION 已删除重复项;删除 DISTINCT。
  4. 没有索引,所有这些查询都会进行全表扫描。 创建以下(覆盖)索引:
    CREATE INDEX i_10_11_all on "Finance New"("10","11", "2","3","4","5","6","7","8","9");
    CREATE INDEX i_11_10_all on "Finance New"("11","10", "2","3","4","5","6","7","8","9");
    CREATE INDEX i_2_1_5 on "Finance New"("2", "1","5");
    CREATE INDEX i_3_1_5 on "Finance New"("3", "1","5");
    -- and so on for 4..9

【讨论】:

  • 我会在星期一试试这个。我很确定我可以实现除 CREATE 语句之外的所有语句,但我将先试一试。如果我记得,有一个 GUI 选项可以将列用作索引,但我不知道它是否能实现您上面的语句。
  • 如果不能创建多列索引,至少尝试在所有列上建立单列索引。
  • 我只能在一个列上创建它,所以我会尝试这个。我没有忘记这一点,当我能够回到这个项目时,我会尝试这个。
  • 我无法使用此实现添加索引。但是,我通过重新设计数据的呈现方式将其分解为更小的数据块,从而将其速度提高了大约 2 倍。我添加了一种在报告中请求特定数据子集的方法,并修改了我的原始查询以将其合并,因此它搜索表的子集,而不是全表扫描。让我知道我怎样才能给你留下任何代表。我怀疑您的解决方案会奏效,感谢您提供的信息。
猜你喜欢
  • 2015-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多