2015-02-07 124 views
-1

我将每个交易日的所有权益交易存储在表中。该表包含数百万行。由于在同一时间和第二次,可能有2个或更多的事务发生,并且源数据也没有任何主键。所以我没有添加任何主键到表中。但是做任何查询都很慢,大约60 - 120secs。如何加快SQL查询速度

这里的结构:MySQL和InnoDB的,utf8_general_ci

Ticker varchar(15) 
ReleaseDT datetime 
Order int(1) 
Price decimal (7,3) 
Volume bigint(13) 
Amount bigint(13) 
NoOfLot int(11) 
Session varchar(3) 
Source varchar(15) 
TimeStamp timestamp 

功能:

  1. 获得通过每天或整个一段时间的价格每个股票成交量。
  2. 查看每天有多少个买入和卖出股票的总量
  3. 进一步看点2,我会将它分为早上总买入量和早盘总卖量。

问题: 1.由于没有可找到的唯一项目,此表格的主键是否会影响查询速度?

  1. 我应该只添加一个像ID这样的auto_incremental#,它会自己创建吗?它对查询速度有帮助吗?

  2. 有些查询需要我60-120秒,任何方式来改善上述表?像索引?如果是,请告知如何。

我将使用php进行网络查询和输出,有时还会使用vb.net从mysql服务器进行查询。

例如:

select Ticker, ReleaseDT as 'Last Update',Price, convert(sum(case when iOrder = 1 then Amount else 0 end),decimal(9,0)) as TtlBuyAmt, 
convert(sum(case when iOrder = -1 then Amount else 0 end),decimal(9,0)) as TTlSellAmt, 
convert(sum(case when iOrder = 0 then Amount else 0 end),decimal(9,0)) as TTlUndetAmt, 
convert(sum(case when iOrder = 1 then Amount else 0 end)/sum(case when iOrder = -1 then Amount else 0 end),decimal(9,0)) as TTlBuySellRatio, 
sum(case when iOrder = 1 and Session = 'AM' then Amount else 0 end) as BuyAmtAM , 
SUM(CASE WHEN iOrder = 1 and Session = 'PM' then Amount else 0 end) as BuyAmtPM , 
SUM(CASE WHEN iOrder = -1 and Session = 'AM' then Amount else 0 end) as SellAmtAM, 
SUM(CASE WHEN iOrder = -1 and Session = 'PM' then Amount else 0 end) as SellAmtPM , 
convert(SUM(CASE WHEN iOrder = -1 and Session = 'PM' then Amount else 0 end)/SUM(CASE WHEN iOrder = -1 and Session = 'AM' then Amount else 0 end),decimal(5,2)) as SellPMAMRatio, 
sum(Amount) as TotalAmt, 
convert(sum(case when iOrder = 1 then Amount else 0 end) - sum(case when iOrder = -1 then Amount else 0 end),decimal(9,0)) as NetAmount 
FROM Trade 
WHERE Ticker = '1 HK EQUITY' and DATE(ReleaseDT) between '20150102' and '20150104' 
GROUP BY Ticker, date(ReleaseDT), Price 
ORDER BY Ticker ASC, Price DESC 

这需要> 60secs来运行,什么方法能改进?

SELECT * FROM AS2046.BlockTrade_EOD where Ticker = '1 HK EQUITY' and Date(ReleaseDT) > '20150102' Group by Price 

使用EXPLAIN ...和结果如下:

# id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra 
'1', 'SIMPLE', 'BlockTrade_EOD', 'ALL', NULL, NULL, NULL, NULL, '2327212', 'Using where; Using temporary; Using filesort' 
+1

请在您的问题中做一个'EXPLAIN SELECT [...]'EXPLAIN SELECT [...]并将结果发布到您的问题中。另外请从相关表格中发布完整的“CREATE TABLE”语句。 – Bjoern 2015-02-07 12:05:53

+0

欢迎使用堆栈溢出。毫无疑问,索引将帮助您查询此表。为了帮助您,我们需要查看一些速度较慢的查询。请编辑您的问题以包含它们。同时,阅读**复合覆盖指标。**添加了 – 2015-02-07 12:35:26

+0

。这是常用的sql查询之一。 – Trader 2015-02-07 12:57:21

回答

0

,因为这仍然是非常有限的输入一个相当宽泛的问题,我会尽量给一些有限的忠告:

  1. 主键不一定会加快查询速度。它很大程度上取决于您的查询类型。通常情况下,索引(不一定是主键)从你发布的查询看来,似乎有可能性,因为Ticker上的索引(不是主键,因为Ticker不是唯一的,因为看起来)可能会加速操作(“WHERE Tickler ='...'“)。 ReleaseDT也是索引的候选人 - 可能与Ticker一起使用。但是,所有这一切都取决于您的表格中的数据......例如:有多少行具有Ticker值“1 HK EQUITY”。

  2. 不大可能会加入人工PK加速操作。许多数据库自己添加一个人工PK。另外我也没有看到人造PK如何帮助选择。当然,主键在其他选择中可能很有用。

  3. 请参阅1.我最好的猜测是索引(或甚至PK,取决于您的数据)的代码和/或ReleaseDT。你看到的很可能是一个“全表扫描” - 数据库引擎必须处理所有你的一百万行的一个SELECT。索引可以显着减少操作 - 取决于数据库中的数据。

我会建议您检查您的表的内容(例如有多少行包含“1 HK公平”为股票代码。如果只有行的一小部分这样做,就在此列上添加索引。

但是:!当心 - 上表中的每一指标再增加复杂度所有写入表,因为索引必须保持

需要进一步的建议,将需要更多的数据

1

一个独特的,自动递增的主键很有用,原因很多 - 例如就像你想更新或删除数据一样。但是,如果您没有外键关系,则不是绝对必要的。

为您的查询,综合指数应该有所帮助:

create index idx_Trade_ReleaseDT on Trade(Ticker, ReleaseDT) 

但是,你需要修复的where条款。如果ReleaseDt没有时间组件,然后使用:

WHERE Ticker = '1 HK EQUITY' and 
     ReleaseDT between DATE('2015-01-02') and DATE('2015-01-04') 

或者,如果ReleaseDT能有时间分量:

WHERE Ticker = '1 HK EQUITY' and 
     ReleaseDT >= DATE('2015-01-02') and 
     ReleaseDT < DATE('2015-01-05') 
+0

首先感谢。创建索引期间,我失去了连接。 另外,我在'20150102'和'20150104'之间使用Date(ReleaseDT),它应该符合您的建议。 – Trader 2015-02-07 13:47:17

+1

@交易者。 。 。我不认为这个构造会使用索引。您通常需要“空白”列才能利用索引。 – 2015-02-07 16:41:27

0

首先,应该ReleaseDT是DATETIME,而不仅仅是日期?假设有一个TIME组件...

如果表是InnoDB,那么你的真的应该有一个明确的PRIMARY KEY。 (如果是MyISAM的,没关系。(请提供SHOW CREATE TABLE)

添加复合索引INDEX(Ticker, ReleaseDT)不掩饰内心功能列,如DATE(ReleaseDT)。这使得它无法使用索引作为@Gordon说,但更简单:

ReleaseDT >= '2015-01-02' and 
ReleaseDT < '2015-01-05' 

我喜欢这一点,如果我知道有多少天,不想打的日期算法:

ReleaseDT >= '2015-01-02' and 
ReleaseDT < '2015-01-02' + INTERVAL 3 DAY 

没有必须改变,

GROUP BY Ticker, date(ReleaseDT), Price 

也许

convert(sum(case when iOrder = -1 then Amount else 0 end),decimal(9,0)) 

可以简化为

SUM(IF(iOrder = -1, Amount, 0)) 

如果ReleaseDT并可按日期,然后PRIMARY KEY(北京时间,ReleaseDT)可能是更好的。