我的数据集与股票价格非常相似 - 我每5分钟得到一个平均价格,符号,公司名称。
我需要做的是能够有效:
目前,这是我到目前为止所做的:
Stock Table
ID | name | symbol
Unique between name and symbol (name/symbol can be unique on their own)
Indexed on name, symbol (irrelevant here, but indexed for text search)
Stock Ticks Table
ID | stock_id | price | updated_at
All columns non null
对于问题1(获取给定符号的最新价格),我已经遇到了一些麻烦 - 这与其他问题基本相似:
获取每篇帖子的最新评论,或者基本上是每组最大的查询。事情是我的数据会变得非常大(每5分钟一次),所以我认为这是预优化的好例子。我应该添加current_price
列(或current_prices
表)吗?或者是group by
/ distinct
?如何有效地编写查询?
对于问题2(获取时间间隔价格)我老实说有点困扰如何为此编写查询。请注意,棘手的部分是数据中可能存在漏洞,例如,如果查询是:
get every price per day from June 1 to June 10
并说6月3日没有数据,那么它应该尝试找到最近的时间(过去或现在)
我在Phoenix / Ecto上写这篇文章,所以如果你能用ORM编写它,那将是一个加号但不是必需的。
答案 0 :(得分:1)
假设PostgreSQL v9.6(你没有指定)。
股票表定义
CREATE TABLE stock ( id serial NOT NULL PRIMARY KEY,
name text NOT NULL UNIQUE,
symbol text NOT NULL UNIQUE );
和价格表定义
CREATE TABLE pricing ( id int NOT NULL REFERENCES stock (id),
updated_at TIMESTAMP(0) NOT NULL,
price NUMERIC( 10, 2 ) NOT NULL,
PRIMARY KEY (id, updated_at) );
并按日期加速价格查询而不使用stock_ids
CREATE INDEX ON pricing (updated_at);
示例stock
值为(1,'Queen','BEE'),(2,'Team Fox','FOX')。
示例pricing
值为
(1, '2017-06-17 13:24:59', 12.34),
(1, '2017-06-01 18:00:00', 6.10),
(1, '2017-06-02 17:00:00', 6.20),
(1, '2017-06-03 17:00:00', 6.30),
(2, '2017-06-02 15:00:00', 100.00),
(2, '2017-06-03 15:30:00', 777.00);
获取所有符号的最新价格
SELECT s.*,
(SELECT price
FROM pricing
WHERE id = s.id
ORDER BY updated_at DESC
LIMIT 1) "latest_price"
FROM stock s
WHERE EXISTS (SELECT id FROM pricing p WHERE p.id = s.id);
将使用NULL
条件排除latest_price
的{{1}}值。保留它以获得尚未知道价格的股票的空值。
的替代方案
获取最新价格
是
WHERE EXISTS
到
从6月1日到6月10日每天获得每个价格
首先使用
生成相应的日期SELECT *
FROM stock s
JOIN LATERAL
(SELECT price
FROM pricing p
WHERE p.id = s.id
ORDER BY updated_at DESC
LIMIT 1) latest_price ON true ;
产生
WITH RECURSIVE dates (d) AS (
SELECT '2017-06-01 20:00'::timestamp
UNION ALL
SELECT d + interval '24 hours'
FROM dates
WHERE d < '2017-06-04 20:00'::timestamp
)
SELECT d FROM dates ;
您可以调整以下参数
d
---------------------
2017-06-01 20:00:00
2017-06-02 20:00:00
2017-06-03 20:00:00
2017-06-04 20:00:00
)'2017-06-01 20:00'::timestamp
)'2017-06-04 20:00'::timestamp
)使用日期
interval '24 hours'
得到例如
WITH RECURSIVE dates (d) AS (
SELECT '2017-06-01 20:00'::timestamp
UNION ALL
SELECT d + interval '24 hours'
FROM dates
WHERE d < '2017-06-04 20:00'::timestamp
)
SELECT symbol, CAST( d AS date ) "day", price, updated_at
FROM stock s
CROSS JOIN dates
JOIN LATERAL (
SELECT updated_at, price
FROM pricing p
WHERE p.id = s.id AND p.updated_at <= d
ORDER BY p.updated_at DESC
LIMIT 1
) latest_prices ON true
ORDER BY 1, 2, 4, 3 ;
-- orders same id = name blocks;
-- use 2, 1, 4, 3 to get same date blocks