如何获得超过15分钟前的最新条目?

时间:2013-12-11 20:56:46

标签: mysql

问题

我们从供应商那里得到股票价格和交易,为了加快速度,我们在交易时缓存交易(每股1次交易不是很多)。我们有大约2,000只股票,所以从技术上讲,我们预计每分钟交易量高达120,000(2,000 * 60)。现在,这些价格是实时的,但为了避免支付许可费用以向客户显示这些数据,我们需要显示价格延迟15分钟。 (我们需要内部的实时价格,这就是为什么我们购买并支付它们(它们并不便宜!)

我觉得我已经尝试了所有的东西,而且我遇到了无数的问题。

我尝试过的事情

1

每隔15秒运行一次cronjob,运行一个查询,检查超过15分钟之前该股票的交易(对于加入):

SELECT
    MAX(`time`) as `max_time`,
    `stock_id`
FROM
    `stocks_trades`
WHERE
    `time` <= DATE_SUB(NOW(), INTERVAL 15 MINUTE)
AND
    `time` > '0000-00-00 00:00:00'
GROUP BY
    `stock_id`

这非常快 - 1.8秒,行数约为2,000,000,但以下内容非常慢:

SELECT
    st.id,
    st.stock_id
FROM
    (
        SELECT
            MAX(`time`) as `max_time`,
            `stock_id`
        FROM
            `stocks_trades`
        WHERE
            `time` <= DATE_SUB(NOW(), INTERVAL 15 MINUTE)
        AND
            `time` > '0000-00-00 00:00:00'
        GROUP BY
            `stock_id`
    ) as `tmp`
INNER JOIN
    `stocks_trades` as `st`
ON
    (tmp.max_time = st.time AND tmp.stock_id = st.stock_id)
GROUP BY
    `stock_id`

..需要大约180-200秒,这太慢了。 timestock_id都有一个索引(个别)。

2

在InnoDB / MyISAM之间切换。我想我需要InnoDB(我们从多个线程插入很多行,我们不想在每个插入之间阻塞) - InnoDB在插入时似乎更快,但在读取时速度慢(我们需要两者,显然)。

第3

每天优化表格。还是很慢。

我认为可能有所帮助:

  1. 使用int代替DateTime。也许(因为市场从9-22开放)保持一个自定义的int时间,这将是“今天早上9点以来的秒”并使用与上面相同的方法(它似乎使some不同,虽然不是很多)
  2. 使用MEMORY而不是InnoDB - 即使我们有足够的内存,也可能不是每15分钟约18,000,000行的最佳选择
  3. 在接收价格的应用程序中保存价格/ stockID /时间在内存中(我不知道这与使用MEMORY有什么不同,除了我的代码可能会比MySQL自己的代码更差)
  4. 继续删除超过15分钟的交易,希望它能加快查询速度
  5. 我刚才没有想到的一些神奇的查询,它完美地使用了索引并且做了神奇的事情
  6. 在花了大约12个小时试图绕过这个和不同的解决方案后放弃并杀死一个人

3 个答案:

答案 0 :(得分:0)

假设您有一个自动递增ID作为stock_trades上的主键(称之为stock_trade_id),您可以在内部查询中选择max('stock_trade_id')作为'last_id',然后对'last_id执行内部联接'='stock_trade_id'因此您将加入您的PK,并且在您的主要加入时没有日期比较。

SELECT
st.id,
st.stock_id
FROM
(
    SELECT
        MAX(`stock_trade_id`) as `last_id`,
        `stock_id`
    FROM
        `stocks_trades`
    WHERE
        `time` <= DATE_SUB(NOW(), INTERVAL 15 MINUTE)
    AND
        `time` > '0000-00-00 00:00:00'
    GROUP BY
        `stock_id`
) as `tmp`
INNER JOIN
    `stocks_trades` as `st`
ON
   (tmp.last_id = st.stock_trade_id)
GROUP BY
   `stock_id`

答案 1 :(得分:0)

如果你运行这样的事情会怎么样?如果需要,尝试更改它以包含价格的正确列名:

SELECT st.id, st.stock_id
FROM stock_trades as st
WHERE   time <= DATE_SUB(NOW(), INTERVAL 15 MINUTE)
AND time > DATE_SUB(NOW(), INTERVAL 45 MINUTE)
AND not exists (select 1 from stock_trades as st2 where st2.time <= DATE_SUB(NOW(), INTERVAL 15 MINUTE) and st2.stock_id = st.stock_id and st2.time > st.time)
希望它有所帮助!

答案 2 :(得分:0)

由于你要在两列(stock_id, time)上加入你的子查询,MySQL应该能够在两个中使用复合索引,而它不能使用它们您已经拥有的各个列索引。

ALTER TABLE `stocks_trades` ADD INDEX `idx_stock_id_time` (`stock_id`, `time`)