是否应该在 SQLite 中使用 GROUP BY 在 UNION 上进行 INNER JOIN 花费数小时?

Posted

技术标签:

【中文标题】是否应该在 SQLite 中使用 GROUP BY 在 UNION 上进行 INNER JOIN 花费数小时?【英文标题】:Should an INNER JOIN on a UNION with a GROUP BY take hours in SQLite? 【发布时间】:2011-05-11 19:15:09 【问题描述】:

我正在尝试学习 SQLite 并寻找加快查询速度的技术。当我很容易进入 mega 秒时,我在这里看到一些人试图挤出 ms。我有一个带有四个表的 SQLite 数据库,尽管我只查询三个表。这是查询(我使用 R 来调用查询):

SELECT a.date, a.symbol, SUM (a.oi*a.contract_close) AS oi, c.ret, c.prc
    FROM (SELECT date, symbol, oi, contract_close FROM ann
            UNION
            SELECT date, symbol AS sym, oi, contract_close FROM qtr
            WHERE oi > 100 AND contract_close > 0 AND date > 20090600) a
    INNER JOIN
    (SELECT date, symbol || '1C' AS sym, ret, prc FROM crsp
            WHERE prc > 5 AND date>20090600) c
    ON a.date = c.date AND a.symbol = c.sym
    GROUP BY a.date, a.symbol

我在每个表上都有一个按日期和符号排列的索引,只是 VACUUMed,但它仍然很慢,就像一个多小时内一样(注意我正在寻找一个六个月的子集......我真的很想查询回 2003 年)。

这只是缓存大小问题吗?我有一台相对较新的笔记本电脑(配备 4gb RAM 的 MacBook Pro)。谢谢!

这是.schema

CREATE TABLE ann 
( "date" INTEGER,
 symbol TEXT,
 contract_type_1 TEXT,
 contract_type_2 TEXT,
 product_type TEXT,
 block_volume INTEGER,
 oi_change INTEGER,
 oi INTEGER,
 efp_volume INTEGER,
 total_volume INTEGER,
 name TEXT,
 contract_change INTEGER,
 contract_open INTEGER,
 contract_high INTEGER,
 contract_low INTEGER,
 contract_close INTEGER,
 contract_settle INTEGER 
);
CREATE TABLE crsp 
( "date" INTEGER,
 symbol TEXT,
 permno INTEGER,
 prc REAL,
 ret REAL,
 vwretd REAL,
 ewretd REAL,
 sprtrn REAL 
);
CREATE TABLE dly 
( "date" INTEGER,
 symbol TEXT,
 expiration INTEGER,
 product_type TEXT,
 shares_per_contract INTEGER,
 "open" REAL,
 high REAL,
 low REAL,
 "last" REAL,
 settle REAL,
 change REAL,
 total_volume INTEGER,
 efp_volume INTEGER,
 block_volume INTEGER,
 oi INTEGER 
);
CREATE TABLE qtr 
( "date" INTEGER,
 symbol TEXT,
 total_volume INTEGER,
 block_volume INTEGER,
 efp_volume INTEGER,
 contract_high INTEGER,
 contract_low INTEGER,
 contract_open INTEGER,
 contract_close INTEGER,
 contract_settle INTEGER,
 oi INTEGER,
 oi_change INTEGER,
 shares_per_contract INTEGER,
 expiration INTEGER,
 product_type TEXT,
 unk TEXT,
 name TEXT 
);
CREATE INDEX idx_ann_date_sym ON ann (date, symbol);
CREATE INDEX idx_crsp_date_sym ON ann (date, symbol);
CREATE INDEX idx_dly_date_sym ON ann (date, symbol);
CREATE INDEX idx_qtr_date_sym ON ann (date, symbol);

【问题讨论】:

【参考方案1】:

在没有 INNER JOIN 的情况下运行速度有多快。检查连接两半的速度。

试试

从 C 中选择符号并按日期排序。 内部联接到联合 A 而不是表 C。 在联合的一半中将符号的别名作为 sym 删除,或者在两半中删除别名。

【讨论】:

【参考方案2】:

您没有提到关键信息,即每个表中有多少行以及结果集中有多少行。除非您拥有非常庞大的数据集,否则查询不应花费一个小时。

也就是说,关于您的查询,我注意到了几点:

    我假设您知道在您的 UNION 中,WHERE 子句仅适用于第二个表,并且您将包含整个“ann”表?

    UNION ALL 通常比普通 UNION 更快,除非您确实需要普通 UNION 提供的重复数据删除。

    您无需对 JOIN 两侧的日期字段重复过滤。一侧就足够了,根据您放置过滤器的 JOIN 的哪一侧,您可能会获得不同的速度结果。在这两个地方都使用它可能会欺骗查询优化器。

    我不确定“AS sym”在 UNION 的第二个 SELECT 中做了什么,因为该列在输出中将被命名为“symbol”(来自 UNION 中的第一个 SELECT),而你'重新依赖主 SELECT 语句中的名称符号。

    在您的主 SELECT 语句中,聚合函数中没有 c.ret 和 c.prc,但您没有将它们包含在 GROUP BY 中,因此我不清楚您期望的值是什么如果 c 包含 GROUP BY 集的多行,请查看结果。

    无法优化 JOIN,因为您正在计算其中一个 JOIN 值作为内部 SELECT 的一部分。我不确定是否有一种巧妙的方法可以将 JOIN 条件重写为可优化,而无需将计算的符号值存储在 crsp 中。

    根据符号和日期值的分布,您可能希望反转索引中列的顺序(但前提是您解决了计算符号值的问题)。

    李>

【讨论】:

正在处理这些,谢谢!行数为:ann-1.5m, qtr-2.1m, crsp-14m SELECT FROM crsp 中的字符串连接在速度方面一定会伤害你。 是的,我认为它确实是......我做了你推荐的其他更改,但 30 分钟后它仍在进行。我希望保持数据库完好无损,但我会转储 crsp 表并查看“1C”。 救命稻草。 || 操作员让我很生气。我可能会再修补一些,但现在快得多了。谢谢!

以上是关于是否应该在 SQLite 中使用 GROUP BY 在 UNION 上进行 INNER JOIN 花费数小时?的主要内容,如果未能解决你的问题,请参考以下文章

sqlite GROUP BY 和 ORDER

在 SQLite 的 GROUP_CONCAT 函数中使用 ORDER BY 子句

核心数据:是不是可以在 group by 中使用自定义功能

在 SQLite 中有效的 SQL Group By 在 Postgres 中无效

group_concat sqlite 和 order by

将使用 GROUP BY 的查询从 MySQL 转换为 Postgres 和 SQLite