SQL查询效率低下 - 我该如何改进?

时间:2014-12-01 11:30:11

标签: sql sqlite

我在SQLite中使用下面的SQL代码来获取包含交易的表中的交易列表,然后将其与当天的总投资组合值相结合,从具有一组工具的头寸和价格数据的持股表中

馆藏表有大约150000条记录,交易表大约有1700条

SELECT t.*, (SELECT     p.adjclose FROM prices AS p
                WHERE   t.instrument = p.instrument
                        AND p.date = "2013-02-28 00:00:00") as close,
            su.mv as mv
            FROM trades AS t
left outer join 
      (SELECT h.date, SUM(h.price * h.position) as mv FROM holdings AS h
        WHERE h.portfolio = "usequity" 
        AND h.date >= "2013-01-11 00:00:00"
        AND h.date <= "2013-02-2"
        GROUP BY h.date) as su
     ON t.date = su.date         
   WHERE t.portname = "usequity"
                AND t.date >= "2013-01-11 00:00:00"
                AND t.date <= "2013-02-28 00:00:00";

运行SQL代码返回

[2014-12-01 19:21:00] 123 row(s) retrieved starting from 1 in 572/627 ms

对于小型数据集来说,这看起来真的很慢。两个表都按仪器和日期编制索引。

我不知道如何动态索引表su,所以我不知道如何改进这段代码。非常感谢任何帮助。

修改

解释查询计划显示

selectid,order,from,detail
1,0,0,"SEARCH TABLE holdings AS h USING AUTOMATIC COVERING INDEX (portfolio=?) (~7 rows)"
1,0,0,"USE TEMP B-TREE FOR GROUP BY"
0,0,0,"SCAN TABLE trades AS t (~11111 rows)"
0,1,1,"SEARCH SUBQUERY 1 AS su USING AUTOMATIC COVERING INDEX (date=?) (~3 rows)"
0,0,0,"EXECUTE CORRELATED SCALAR SUBQUERY 2"
2,0,0,"SEARCH TABLE prices AS p USING INDEX p1 (instrument=? AND date=?) (~9 rows)"

1 个答案:

答案 0 :(得分:1)

prices上的查询速度很快(它使用两列的索引)。

您可以为su子查询创建临时表并为其添加索引,但AUTOMATIC INDEX表示数据库已在执行此操作。

holdings上的查找是使用临时索引完成的;你应该为它创建一个显式索引。 (portfoliodate上的索引会更有效率。)

您可以通过动态查找holdings的值来避免需要临时表,就像您已经在收盘价一样(但如果有很多交易,这可能不会有所改善)同一天):

SELECT t.*,
       (SELECT p.adjclose
        FROM prices AS p
        WHERE p.instrument = t.instrument
          AND p.date = '2013-02-28 00:00:00'
       ) AS close,
       (SELECT SUM(h.price * h.position)
        FROM holdings AS h
        WHERE h.portfolio = 'usequity'
          AND h.date = t.date
       ) AS mv
FROM trades AS t
WHERE t.portname = 'usequity'
  AND t.date BETWEEN '2013-01-11 00:00:00'
                 AND '2013-02-28 00:00:00';