如何加快SQL查询速度

时间:2015-02-07 12:01:45

标签: mysql database performance time-series

我将每个交易日的所有股权交易存入表中。该表包含数百万行。因为在同一时间和第二次,可能发生2次或更多次事务,并且源数据也没有任何主键。所以我没有向表中添加任何主键。但是做任何查询都非常慢,大约60到120秒。

这里有结构: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点,我将它分为早上总买入和早上总卖出。
  4. 问题:  1.由于没有我能找到的唯一项目,此表的主键是否会影响查询速度?

    1. 我只需要添加一个类似ID的auto_incremental#,它会自行创建吗?它对查询速度有帮助吗?

    2. 有些查询需要我60-120秒,有什么方法可以改进上表吗?喜欢索引?如果是,请告知如何。

    3. 我将使用php进行Web查询和输出,有时使用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
      

      运行时需要> 60秒才能改进?

      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'
      

3 个答案:

答案 0 :(得分: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') 

答案 1 :(得分:0)

因为这仍是一个相当广泛的问题,输入非常有限,我会尝试提供一些有限的建议:

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

  2. 添加人工PK加速操作的可能性非常小。许多数据库自己添加了人工PK。另外,我没有看到人工PK如何帮助这个选择。当然,主键在其他选择中可能很有用。

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

  4. 我建议检查表的内容(例如,有多少行包含“1 HK EQUITY”作为Ticker。如果只有一小部分行这样做,则开始在此行上添加索引。

    但是:注意 - 表上的每个索引都会增加对表的所有写入的复杂性,因为必须维护索引。

    如需进一步的建议,则需要更多数据!

答案 2 :(得分:0)

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

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

添加复合索引INDEX(Ticker, ReleaseDT) AND 不会隐藏函数内的列,例如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可以是DATE,则PRIMARY KEY(Ticker,ReleaseDT)可能更好。