MYSQL - 从大表中的第二行中选择数据

时间:2012-11-26 07:16:32

标签: mysql optimization select row

我有一个外部第三方程序实时将数据库导出到mysql,我想显示数据用于报告。所以,我无法改变结构,因为它是实时同步的。

表结构是这样的

ID | Date       | Transaction
-----------------------------
12 | 2012-11-01 | 200
12 | 2012-11-02 | 250
12 | 2012-11-03 | 150
12 | 2012-11-04 | 1000
12 | 2012-11-05 | 225
....
13 | 2012-11-01 | 175
13 | 2012-11-02 | 20
13 | 2012-11-03 | 50
13 | 2012-11-04 | 100
13 | 2012-11-05 | 180
13 | 2012-11-06 | 195

数据非常庞大,每天都在变大。

我想要做的是基于以下内容构建报告(视图表):

ID | Date       | Transaction | Prev Day Transaction
----------------------------------------------------
12 | 2012-11-01 | 200         | 0
12 | 2012-11-02 | 250         | 200
12 | 2012-11-03 | 150         | 250
12 | 2012-11-04 | 1000        | 150
12 | 2012-11-05 | 225         | 1000
....
13 | 2012-11-01 | 175         | 0
13 | 2012-11-02 | 20          | 175
13 | 2012-11-03 | 50          | 20
13 | 2012-11-04 | 100         | 50
13 | 2012-11-05 | 180         | 100
13 | 2012-11-06 | 195         | 180

我无法获得快速选择语句。目前原始数据已经是283,120行。它每天会增长500行。

我尝试过类似的事情:

SELECT *, (SELECT transaction FROM table as t2 WHERE t1.id=t2.id 
AND t1.date>t2.date ORDER BY t2.date DESC LIMIT 0,1)
FROM table AS t1

它正常工作,但是select语句非常慢。大多数时候,它在操作过程中被切断了。

我需要帮助的是一个非常快速的sql语句,稍后我可以使用它来构建视图表。

4 个答案:

答案 0 :(得分:3)

请参阅此链接:http://sqlfiddle.com/#!2/54a5e/12

select t.id,t.cDate,t.cTrans
  ,(case when @pID=t.id then @pTran else 0 end) as preT 
  ,(@pID :=t.id) as `tID`,(@pTran := t.cTrans) as `tTrans` 
from tb_test_1 as t,(select @pID = 0, @pTran = 0) as t2
order by id,cDate;
必须保留

tIDtTrans列,并且无法在页面上显示。

请原谅我,因为我只懂一点英语!

答案 1 :(得分:2)

尝试此查询 -

SELECT t1.*, COALESCE(t2.transaction, 0) Prev_Day_Transaction FROM trans t1
  LEFT JOIN (SELECT * FROM trans ORDER BY id, date DESC) t2
    ON t1.id = t2.id AND t1.date > t2.date
GROUP BY t1.id, t1.date;

+------+------------+-------------+----------------------+
| id   | date       | transaction | Prev_Day_Transaction |
+------+------------+-------------+----------------------+
|   12 | 2012-11-01 |         200 |                    0 |
|   12 | 2012-11-02 |         250 |                  200 |
|   12 | 2012-11-03 |         150 |                  250 |
|   12 | 2012-11-04 |        1000 |                  150 |
|   12 | 2012-11-05 |         225 |                 1000 |
|   13 | 2012-11-01 |         175 |                    0 |
|   13 | 2012-11-02 |          20 |                  175 |
|   13 | 2012-11-03 |          50 |                   20 |
|   13 | 2012-11-04 |         100 |                   50 |
|   13 | 2012-11-05 |         180 |                  100 |
|   13 | 2012-11-06 |         195 |                  180 |
+------+------------+-------------+----------------------+

将复合索引(id,date)添加到表中。

===========================

ALTER TABLE mt4_daily
  ADD INDEX IX_mt4_daily_DATE (DATE);

ALTER TABLE mt4_daily
  ADD INDEX IX_mt4_daily (ID, DATE);

答案 2 :(得分:1)

通过select语句将表划分为几个,并使用UNION Set运算符将它们连接起来。由于所有集合运算符都是并行运算,因此您可以非常快速地获取数据您可以使用表格中的唯一数字列来划分数据。 e.g。

select * from tbl_x where col1%3=0 union
select * from tbl_x where col1%3=1 union
select * from tbl_x where col1%3=2 ...

上面的sql查询以并行方式划分数据和提取

答案 3 :(得分:1)

我会尝试写这样的查询:

SELECT
  tbl.ID,
  tbl.Date,
  tbl.Transaction,
  COALESCE(tbl1.Transaction,0) as PrevDay
FROM
  tbl left join tbl tbl1
  on tbl.ID = tbl1.ID
     and tbl.Date = tbl1.Date + INTERVAL 1 DAY

(只有在确保表格包含所有日期时才有效,如果您错过了一天,第二天将始终显示PrevDay为0,我不确定这是否是您需要的。)

编辑:我会尝试这个解决方案,即使有些日子不见了,也会有效:

SELECT
  tbl.id,
  tbl.date,
  tbl.Transaction,
  COALESCE(tbl1.Transaction,0) as PrevDay
FROM
  (SELECT tbl.id, tbl.date as d1, max(tbl1.ddate) as d2
   FROM tbl LEFT JOIN tbl tbl1
        ON tbl.id = tbl1.id and tbl.date>tbl1.date
   GROUP BY tbl.id, tbl.date) t
  LEFT JOIN tbl on tbl.id = t.id and DATE(tbl.ddate) = DATE(t.d1)
  LEFT JOIN tbl tbl1 ON tbl1.id = t.id and DATE(tbl1.date) = DATE(t.d2)