【问题标题】:MYSQL - Selecting data from second row in a large tableMYSQL - 从大表的第二行中选择数据
【发布时间】:2012-11-27 17:45:30
【问题描述】:

我有一个外部 3rd 方程序将数据库实时导出到 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 语句,以后我可以用它来构建视图表。

【问题讨论】:

  • What speed you are getting for Select * from trans where id='12'
  • 嗨,Sami,我只是在随机用户测试。来自 PHPMyadmin,它在 0.0008 秒内花费了 274 个数据(显示 0 - 29 个数据)。 edit 如您所见,直接调用表格非常快并且没有问题。问题仅出现在尝试获取先前数据时。我似乎无法获得正确的选择语句。

标签: mysql optimization select row


【解决方案1】:

查看此链接: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 列必须保留,不能在页面上显示。

请原谅我只会一点英文!

【讨论】:

  • 这几乎是完美的。在sqlfiddle中,没关系。但是当我在我的真实数据库上进行测试时,'preT' 填充了 [BLOB - 1B],而不是我的数字(双重类型转换)。您或其他人可以帮忙吗?
  • 耶哈。我已经摆弄它并找到了更正。使用 ':=' 而不是 '=' 来修正公式,并使用 '0.0' 而不是 '0' 将其类型转换为十进制。完美的线应该是....... (select @pID := 0.0, @pTran := 0.0) as t2
  • 哎呀。忘记对所有试图帮助和回答的人说声谢谢。我非常感谢您的时间和精力。我只是通过询问获得了许多新知识。 :D 当然特别感谢八宝奇的正确回答。再次 TQ 伙计们(和女孩,如果有的话)
【解决方案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、日期)。

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

ALTER TABLE mt4_daily
  ADD INDEX IX_mt4_daily_DATE (DATE);

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

【讨论】:

  • 感谢 Devart 的尝试,但代码仍然很慢(甚至没有运行,等了 30 秒后我退出了脚本)。我更改了表名和列名我还添加了 WHERE id='112' GROUP BY... LIMIT 0,50 以使其更小。我希望它在不到一秒的时间内运行,只有 50 行,但它需要很长时间。能不能再帮忙。 tq.
  • 您是否添加了建议索引 - (id, date)?我认为您还需要添加索引(日期)。
  • 您好 Devart,来自 phpmyadmin,索引似乎已经存在。 keyname Primary, BTREE, Unique, No Packed, Field=ID & Date, Cardinality= 0 & 283120, COLLATION A........ Keyname INDEX_ID, BTREE, No Unique, No Packed, Field=ID, cardinality=0 , Collat​​ion=A ..... keyname INDEX_DATE, BTREE, No unique, No Packed, Field=time, cardinality=0, Collat​​ion=A.... 而且我担心改变结构会干扰实时同步.但是,如果您坚持任何更改,我会尝试将其复制到新的测试 PC 中。时间。
  • 你能显示表结构 - CREATE TABLE 吗?运行 SHOW CREATE TABLE 语句。
  • 嗨,Devart,我从 phpmyadmin 导出并删除了多余的数字字段(所有双重类型转换)。如果不存在则创建表 mt4_daily (ID int(11) NOT NULL, DATE datetime NOT NULL, BALANCE double NOT NULL, PRIMARY KEY (LOGIN,TIME), KEY INDEX_LOGIN ( LOGIN), KEY INDEX_TIME (TIME) ) ENGINE=MyISAM 默认字符集=utf8;
【解决方案3】:

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

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查询分数据并行取数

【讨论】:

  • 感谢并行处理信息。我会记住的。但是,我的表基本上有一个“id”(如用户 ID)和“日期”,有点像配对主键。你建议我如何划分表格?我基本上想要前一天的数据,这个表格划分对我来说是新的。时间。
  • 我认为没关系,您将 id 列作为数值对吗??.. 只需单独使用该 user_id 列。
  • 好的。我是这里的新手。请原谅我问了一些你可能会觉得很明显的问题。我尝试了 {SELECT * FROM table WHERE id=112 AND id%2 ORDER BY date LIMIT 0,30} 但它没有运行。
  • 检查一下..sqlfiddle.com/#!2/fb64be/8我把它分成两部分,如果你想让它更多..使用3并联合它3次等等..
  • Tq 切拉。我明白了,我现在明白了这个概念。我试试看,虽然还是很困惑如何分离复合索引。
【解决方案4】:

我会尝试这样编写查询:

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)

【讨论】:

  • 谢谢你。您的代码几乎可以正常工作。问题是,我的表有一个 DATETIME,所以 {+INTERVAL 1 DAY} 并不总是有效。你有什么建议吗?另外,如果可能的话,我会度过最后一天,因为有时会有假期,例如周五至周一。我希望周一有上周五的数据,如果这不是太多要求的话。时间。
  • @MartinIvanovich 使其与 datetime 一起工作,您可以使用:and DATE(tbl.Date)=DATE(tbl1.Date + INTERVAL 1 DAY) 但要支持前几天而不是第 1 天 ...您可以使用子查询,这有效,但这也意味着它会慢得多..我仍在考虑是否有更快的解决方案...
  • @MartinIvanovich 看到我更新的答案,新查询肯定比我的第一个查询慢,但我相信它应该可以工作....
猜你喜欢
  • 1970-01-01
  • 2011-03-17
  • 2013-07-16
  • 2012-09-13
  • 2023-04-06
  • 1970-01-01
  • 1970-01-01
  • 2020-03-21
  • 1970-01-01
相关资源
最近更新 更多