我正在使用Golang和Postgres来过滤一些财务数据。我有一个Postgres数据库,它有一个包含单个股票市场的表(如果这是正确的术语)。此表包含id,symbol,date,open,high,low,close和volume的列。行总数为6,610,598,不同股票(符号)的数量为2174。
现在我想要做的是过滤该表中的数据,然后保存到另一个表中。所以第一个包含原始数据,第二个包含已清理的数据。
我们有三个参数,一个日期(EVALDATE)和两个整数(MINCTD& MINDP)。首先,我们必须只选择那些将通过我们最小日历交易日参数的股票。因此将选择(注意:我们使用golang)
symbols []string got its value from ( Select distinct symbol from table_name; )
[]filteredSymbols
var symbol, date string
var open, high, low, close float64
var volume int
for _, symbol := range symbols {
var count int
query := fmt.Sprintf("Select count(*) from table_name where symbol = '%s' and date >= '%s';", symbol, EVALDATE)
row := db.QueryRow(query)
if err := row.Scan(&count); err != nil ........
if count >= MINCTD
filteredSymbols = append(filteredSymbols, symbol)
}
基本上,上面的操作只询问从EVALDATE到当前日期(数据中的最新日期)有足够行数的符号,这些符号将满足MINCTD。上述操作耗时 30分钟
如果符号满足上面的第一个过滤器,它将经过第二个过滤器,它将测试在该时间段内(EVALDATE到LATEST_DATE)是否有足够的行包含完整数据(没有值的OHLC)。因此,下面的查询用于过滤通过上述过滤器的符号:
Select count(*) from table_name where symbol='symbol' and date>= 'EVALDATE' and open != 0 and high != 0 and low != 0 and close != 0;
此查询 36分钟。
在获得通过两个过滤器的符号片段后,我将使用postgres查询再次获取其数据,然后开始批量插入另一个表。
所以 1小时6分钟是不可接受的。那我该怎么办?抓取所有数据,然后在内存中使用Golang进行过滤?
答案 0 :(得分:1)
我从问题中注意到了一些事情。
尽量避免扫描600万行以达到2174个值(即避免Select distinct symbol from table_name;
)。你没有(或者你可以建立)一个主表"带有符号主键的符号?
合并您的查询以测试数据,如下所示:
select
count(*) c1
, count(case when open != 0 and high != 0 and low != 0 and close != 0 then 1 end) as c2
from table_name
where symbol='symbol'
and date>= 'EVALDATE'
(符号,日期)的索引有助于提高绩效。
答案 1 :(得分:0)
在Go中,在28.7秒内为3,142个符号清理7,914,698行,这比2,174个符号的6,610,598行优于3,960秒(1小时6分钟)。
输出:
$ go run clean.go
clean: 7914698 rows 28.679295705s
$ psql
psql (9.6.6)
peter=# \d clean
Table "public.clean"
Column | Type | Modifiers
--------+------------------+-----------
id | integer |
symbol | text | not null
date | date | not null
close | double precision |
volume | integer |
open | double precision |
high | double precision |
low | double precision |
Indexes:
"clean_pkey" PRIMARY KEY, btree (symbol, date)
peter=# SELECT COUNT(*) FROM clean;
count
---------
7914698
peter=# SELECT COUNT(DISTINCT symbol) FROM clean;
count
-------
3142
peter=# \q
$
clean.go
:
package main
import (
"database/sql"
"fmt"
"strconv"
"time"
_ "github.com/lib/pq"
)
func clean(db *sql.DB, EVALDATE time.Time, MINCTD, MINDP int) (int64, time.Duration, error) {
start := time.Now()
tx, err := db.Begin()
if err != nil {
return 0, 0, err
}
committed := false
defer func() {
if !committed {
tx.Rollback()
}
}()
{
const query = `DROP TABLE IF EXISTS clean;`
if _, err := tx.Exec(query); err != nil {
return 0, 0, err
}
}
var nRows int64
{
const query = `
CREATE TABLE clean AS
SELECT id, symbol, date, close, volume, open, high, low
FROM unclean
WHERE symbol IN (
SELECT symbol
FROM unclean
WHERE date >= $1
GROUP BY symbol
HAVING
COUNT(*) >= $2
AND
COUNT(CASE WHEN NOT (open >0 AND high >0 AND low >0 AND close >0) THEN 1 END) <= $3
)
ORDER BY symbol, date
;
`
EVALDATE := EVALDATE.Format("'2006-01-02'")
MINCTD := strconv.Itoa(MINCTD)
MINDP := strconv.Itoa(MINDP)
res, err := tx.Exec(query, EVALDATE, MINCTD, MINDP)
if err != nil {
return 0, 0, err
}
nRows, err = res.RowsAffected()
if err != nil {
return 0, 0, err
}
}
{
const query = `ALTER TABLE clean ADD PRIMARY KEY (symbol, date);`
_, err := tx.Exec(query)
if err != nil {
return 0, 0, err
}
}
if err = tx.Commit(); err != nil {
return 0, 0, err
}
committed = true
since := time.Since(start)
{
const query = `ANALYZE clean;`
if _, err := db.Exec(query); err != nil {
return nRows, since, err
}
}
return nRows, since, nil
}
func main() {
db, err := sql.Open("postgres", "user=peter password=peter dbname=peter")
if err != nil {
fmt.Println(err)
return
}
defer db.Close()
var ( // one year
EVALDATE = time.Now().AddDate(-1, 0, 0)
MINCTD = 240
MINDP = 5
)
nRows, since, err := clean(db, EVALDATE, MINCTD, MINDP)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("clean:", nRows, "rows", since)
return
}
游乐场:https://play.golang.org/p/qVOQQ6mcU-1
参考文献:
金融市场技术分析:交易方法和应用综合指南,John J. Murphy。
数据库系统简介,第8版,C.J。日期。
PostgreSQL:简介和概念,Bruce Momjian。
PostgreSQL 9.6.6文档,PostgreSQL。