SQLite中的条件FROM子句

SQLite中的条件FROM子句,sql,sqlite,Sql,Sqlite,我正在优化大型SQLite传感器数据库以提高查询性能 为此,我存储了平均数据的多个分辨率,因为目标始终是获得它们的平均值 因此,我将此作为数据: CREATE TABLE "raw_data" ( "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "date" integer NOT NULL, "measurement" integer NOT NULL

我正在优化大型SQLite传感器数据库以提高查询性能

为此,我存储了平均数据的多个分辨率,因为目标始终是获得它们的平均值

因此,我将此作为数据:

CREATE TABLE "raw_data" (
  "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
  "date" integer NOT NULL,
  "measurement" integer NOT NULL
);

CREATE INDEX "idx_date_raw_data"
ON "raw_data" (
  "date" ASC
);

INSERT INTO "raw_data" (id, date, measurement) VALUES
(0, 1546300868,2170),
(1, 1546301078,2160),
(2, 1546301108,2170),
(3, 1546301198,2160),
(4, 1546301498,2150),
(5, 1546301588,2160),
(6, 1546301648,2150),
(7, 1546301707,2140),
(8, 1546301738,2150),
(9, 1546301797,2140);

CREATE TABLE "ten_avg_data" (
  "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
  "date" integer NOT NULL,
  "measurement" integer NOT NULL
);

CREATE INDEX "idx_date_ten_avg_data"
ON "ten_avg_data" (
  "date" ASC
);

INSERT INTO "ten_avg_data" (id, date, measurement) VALUES
(0, 1546300868,2155);
我想查询平均值:

SELECT
  COUNT(*)
FROM
  raw_data
WHERE
  date BETWEEN 1546300868 AND 1546302037;

-- If above count is < 10 do this:
SELECT
  AVG(measurement)
FROM
  raw_data
WHERE
  date BETWEEN 1546300868 AND 1546302037;

-- but if >=10, do this:
SELECT
  AVG(measurement)
FROM
  ten_avg_data
WHERE
  date BETWEEN 1546300868 AND 1546302037
如您所见,SELECT AVGmeasurement对于这两个查询很常见,我只想使from子句有条件

由于原始数据非常庞大,将原始数据和十个平均数据合并在一起是不好的,因为这样会很慢

<> P> >请考虑查询RWAY数据的平均值为1分钟,从TynAvgGi数据得到的平均值为0.5。 在这种情况下,使FROM子句有条件的最佳方法是什么


操场是。

好的,一种方法是在查询所有数据时使用HAVING子句,检查计数*是否大于10。如果不是,则此查询将生成空集。因此,您可以将其用作第二个查询的WHERE子句中不存在的子查询,使第二个查询产生空集,而第一个查询不产生空集。将结果与UNION ALL组合,您将得到不产生空集的结果

SELECT avg(rd1.measurement)
       FROM raw_data rd1
       WHERE rd1.date BETWEEN 1546300868
                              AND 1546302037
       GROUP BY ''
       HAVING count(*) < 10
UNION ALL
SELECT avg(tad1.measurement)
       FROM ten_avg_data tad1
       WHERE tad1.date BETWEEN 1546300868
                               AND 1546302037
             AND NOT EXISTS (SELECT avg(rd1.measurement)
                                    FROM raw_data rd1
                                    WHERE rd1.date BETWEEN 1546300868
                                                           AND 1546302037
                                    GROUP BY ''
                                    HAVING count(*) < 10);
请注意,出于某种原因,为了使用HAVING子句,SQLite需要GROUPBY子句,我们需要按任意奇数常量分组,因为我们实际上希望整个表上有一个分组


但是,我不确定您的方法是否真的有助于提高性能。我不知道SQLite在利用统计信息确定第一次查询的行数将大于或等于10方面有多好。或者它至少会在得到十行时停止第一个查询。如果它不能立即确定,它需要扫描索引idx_date_raw_数据的相关部分,但您没有获得任何信息,或者至少没有获得所需的信息,因为只有一个查询从所有数据中获得平均值…

我认为您最好能做到如下:

WITH rd AS (
      SELECT COUNT(*) as cnt, AVG(measurement) as avg_m
      FROM raw_data
      WHERE date BETWEEN 1546300868 AND 1546302037;
    )
SELECT avg_m
FROM rd
WHERE cnt < 10
UNION ALL
SELECT AVG(measurement)
FROM ten_avg_data
WHERE date BETWEEN 1546300868 AND 1546302037 AND
      (SELECT cnt FROM rd) >= 10;
计数和平均值的成本将非常相似——处理数据的费用


第一个查询超过一分钟似乎太长了。你应该考虑一个关于RWYDATADATE,Realth.< /P>的索引,第一个查询需要花费多少时间来计算RAWI数据的行数?您是否测试了一个同时进行计数和获取平均值的查询?计数*需要3秒,计数*和平均值。。是10秒。怎么可能计数*和平均值。。是10秒,平均值只需要1分钟?因为平均值也用于多个CTE,但我不能发布,我发布了,但它立即得到了-2分。