代码之家  ›  专栏  ›  技术社区  ›  Richard Herron

内部联接是否应通过在sqlite中花费数小时与组联接?

  •  1
  • Richard Herron  · 技术社区  · 14 年前

    我正在尝试学习sqlite并寻找加速查询的技术。我看到这里有一些人想挤出MS,当我很容易进入 兆欧 秒。我有一个带四个表的sqliteDB,尽管我只查询三个表。下面是查询(我使用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
    

    我在每个表上都有一个按日期和符号排列的索引,只是被清空了,但它仍然很慢,就像一小时加上一个小时(注意我在寻找一个六个月的子集…我真的想回到2003年)。

    这只是缓存大小问题吗?我有一台相对较新的笔记本电脑(带有4GB内存的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);
    
    2 回复  |  直到 12 年前
        1
  •  3
  •   Larry Lustig    14 年前

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

    也就是说,我注意到你的一些问题:

    1. 我假设您知道在您的联合中,WHERE子句只适用于第二个表,并且您将包括整个“ann”表?

    2. union all通常比普通union快,除非您确实需要由普通union提供的重复数据消除。

    3. 您不需要为联接两侧的日期字段重复筛选。一个边就足够了,根据放置过滤器的连接的哪一侧,您可能会获得不同的速度结果。通过在两个地方都使用它,您可能会欺骗查询优化器。

    4. 我不确定“as sym”在联合中的第二个select中做了什么,因为该列在输出中(从联合中的第一个select中)将被命名为“symbol”,而您正依赖于主select语句中的名称符号。

    5. 在主select语句中,聚合函数中没有c.ret和c.prc,但在group by中没有包含它们,因此我不清楚如果c包含多行用于group by set,您希望在结果中看到什么值。

    6. 无法优化联接,因为您正在将联接值之一作为内部选择的一部分进行计算。我不确定是否有一种巧妙的方法可以重写连接条件,以便在不将计算的符号值存储在CRSP中的情况下进行优化。

    7. 根据符号和日期值的分布情况,您可能希望颠倒索引中列的顺序(但仅当您解决了计算符号值的问题时)。

        2
  •  1
  •   BillThor    14 年前

    如果没有内部连接,这会有多快。检查连接的两部分的速度。

    尝试

    • 按日期选择和排序C中的符号。
    • 内部连接到接头A而不是表C。
    • 在并集的一半中删除符号的别名sym,或在并集的一半中删除别名sym。