Python sqlite3和查询优化问题

问题描述

我正在使用sqlite3和Python 3.8来构建一个带有以下表格的财务报价数据库操作:

CREATE TABLE "daily_price" (
    "id"    INTEGER,"date"  DATETIME NOT NULL COLLATE NOCASE,"Open"  REAL DEFAULT NULL,"High"  REAL DEFAULT NULL,"Low"   REAL DEFAULT NULL,"Close" REAL DEFAULT NULL,"Volume"    INTEGER DEFAULT NULL,"Adj_Open"  REAL DEFAULT NULL,"Adj_High"  REAL DEFAULT NULL,"Adj_Low"   REAL DEFAULT NULL,"Adj_Close" REAL DEFAULT NULL,"Adj_Volume"    INTEGER DEFAULT NULL,"Dividend"  REAL DEFAULT NULL,"Split" REAL DEFAULT NULL,"Symbol"    TEXT NOT NULL COLLATE NOCASE,PRIMARY KEY("id" AUTOINCREMENT)
);

此表大约有3000万行。在该表上有4个索引,这些索引旨在提高我认为是典型查询的查询性能。

CREATE INDEX "dividend_idx" ON "daily_price" (
    "date"  ASC,"Symbol"    ASC,"Dividend"
) WHERE "Dividend" > 0;

CREATE INDEX "socv_idx" ON "daily_price" (
    "date"  ASC,"Open","Close","Volume"
);

CREATE INDEX "split_idx" ON "daily_price" (
    "date"  ASC,"Split"
) WHERE "Split" <> 1;

CREATE INDEX "symbol_idx" ON "daily_price" (
    "Symbol"    ASC,"date"  ASC
);

我反复构建了不同的索引策略,测试了代表基本用例的查询,观察了性能,然后根据需要使用EXPLAIN QUERY PLAN进行了更深入的研究。

构建索引只需要几分钟,我打算在更新表批量存储之前完全删除它们,然后重新构建它们。但是,它们的容量几乎是磁盘大小的两倍(+ 83%),这只是一个测试数据库,然后再转移到100+ GB更大的磁盘上,因此,如果可以采用更好的方法,我将很高兴听到建议。

在没有背景的情况下,我的问题是一些查询,在这些查询中,优化器将选择一个非最佳索引,从而导致搜索时间激增。例如,如果我接受以下查询:

SELECT Symbol 
FROM daily_price 
WHERE Open > 5 AND Volume > 1000000 
AND Dividend > 0 AND Dividend > 1 
and Dividend/Open>.05;

说明是:

“扫描表日报价格”(使用索引exix_idx)。

它只需要200毫秒,但是如果我尝试使用DISTINCT,GROUP BY或外部SELECT FROM,则需要几分钟的时间...

使用DISTINCT:

SELECT DISTINCT Symbol 
FROM daily_price 
WHERE Open > 5 AND Volume > 1000000 
AND Dividend > 0 AND Dividend > 1 
and Dividend/Open>.05;

使EXPLAIN变为:

扫描表日报价格使用索引符号ID

现在改为使用GROUP BY:

SELECT DISTINCT Symbol 
FROM daily_price 
WHERE Open > 5 AND Volume > 1000000 
AND Dividend > 0 AND Dividend > 1 
and Dividend/Open>.05
GROUP BY Symbol;

还会使EXPLAIN变为:

扫描表日报价格使用索引符号ID

使用子查询的地方:

SELECT DISTINCT Symbol 
FROM( SELECT FROM daily_price 
WHERE Open > 5 AND Volume > 1000000 
AND Dividend > 0 AND Dividend > 1 
and Dividend/Open>.05);

使EXPLAIN再次变为:

扫描表日报价格使用索引符号ID

是什么导致优化器认为在请求DISTINCT符号时执行查找过程中使用symbol_idx索引,或者在其理解获分红_idx索引是获取候选清单最快的方式之前执行GROUP BY的意义? / strong>

我很欣赏我可以将其通过管道传输到pandas DataFrame或以其他方式找到唯一值,但我更希望以SQL方式正确执行此操作。

下面是一些示例查询,这些查询可以按预期运行,并且似乎具有合理的查询计划。最初,我将这些内容包括在内,但它们分散了注意力;但是我认为它们可能有价值,所以离开了它们:

SELECT * FROM daily_price WHERE Symbol = "AAPL";

大约花费15-30毫秒,并返回1万行。详细说明:

搜索表daily_price使用索引index_idx(Symbol =?)

SELECT DISTINCT Symbol FROM daily_price WHERE Symbol Like 'AA%';

大约花费30-40 mS,并返回27行。说明:

搜索表daily_price,使用覆盖索引symbol_idx(符号>?并且 符号

SELECT * FROM daily_price 
WHERE date BETWEEN "1999-11-18 00:00:00+00:00" AND "2000-11-18 00:00:00+00:00";

大约花费175-225 mS,并返回约69万行。说明:

搜索表daily_price使用索引socv_idx(日期>?和日期

SELECT * FROM daily_price 
WHERE date LIKE "1999-11-18 00:00:00+00:00" 
AND Open BETWEEN 5 AND 10 AND Volume > 1000000;

大约花费10-15毫秒,并返回12行。说明:

搜索表daily_price使用索引socv_idx(日期>?和日期

SELECT * FROM daily_price WHERE Dividend > 0;

大约花费65-75 mS,并返回约30万行。说明:

扫描表Daily_price使用索引股息IDx

SELECT * FROM daily_price WHERE Split <> 1;

大约花费15-25毫秒,并返回约6k行。说明:

扫描表Daily_price使用索引split_idx

SELECT * FROM daily_price 
WHERE date BETWEEN "1999-11-18 00:00:00+00:00" AND "2000-11-18 00:00:00+00:00" 
AND Dividend > 0;

大约花费15-25毫秒,并返回约6k行。说明:

搜索表daily_price使用索引股息IDx(日期>?和日期

SELECT * FROM daily_price 
WHERE Symbol = "AAPL" and Dividend > 0;

大约花费10-20毫秒,并返回66行。说明:

搜索表daily_price使用索引index_idx(Symbol =?)

SELECT * FROM daily_price 
WHERE Open > 50 AND Volume > 1000000 
AND Dividend > 0 AND Dividend > 1 
AND Dividend/Open>.05;

大约花费150-200 mS,并返回75行。说明:

扫描表Daily_price使用索引股息IDx

SELECT 
    Symbol 
FROM 
    (SELECT 
        Symbol,Avg(Volume)'avg_vol' 
    FROM 
        daily_price WHERE date BETWEEN "1999-11-18 00:00:00+00:00" AND "2000-11-18 00:00:00+00:00" 
    GROUP BY Symbol)
WHERE avg_vol > 1000000;   

大约花费3000 mS,并返回300行。说明:

id  parent    notused   detail 
 2    0       0         CO-ROUTINE 1
 8    2       0         SEARCH TABLE daily_price USING COVERING INDEX socv_idx (date>? AND date<?)
15    2       0         USE TEMP B-TREE FOR GROUP BY
52    0       0         SCAN SUBQUERY 1

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...