我有两个不同的MySQL表,它们都包含时间序列数据(两者都包含'timestamp'列).除了'timestamp'列之外,这两个表除了'client_id'列之外不共享任何常用功能.
table_a
- id
- client_id
- timestamp
- ...
table_b
- id
- client_id
- timestamp
- ...
Run Code Online (Sandbox Code Playgroud)
两个表都在(client_id,timestamp)上建立索引.
我正在尝试将这两个表组合成一个分页的时间序列.要具体,我的意思是说我试图加载N条记录(与M的偏移量)从联盟table_a和table_b由有序timestamp.
我尝试用这样的语句做到这一点:
(SELECT 'a', id FROM table_a WHERE client_id=1) UNION (SELECT 'b', id FROM table_b WHERE client_id=1) ORDER BY timestamp LIMIT 100;
Run Code Online (Sandbox Code Playgroud)
不幸的是,结果查询似乎抓住了两个表中的所有匹配行,组合,然后应用LIMIT.
请注意,针对各个表的查询非常快:
SELECT 'a', id FROM table_a WHERE client_id=1 ORDER by timestamp LIMIT 100
Run Code Online (Sandbox Code Playgroud)
有没有更好的方法来索引表或编写UNION查询?
您无法在此处充分利用索引,因为两个单独的表中有两个单独的索引.
您可以为每个单独的选择添加限制,但这仅适用于第一页,而不适用于偏移.
如果您愿意放弃"页面"限制加偏移的要求,您可以对其他一些绝对(而不是相对)方式进行分页,例如按天.例如:
(SELECT 'a', id, timestamp FROM table_a WHERE client_id=1 AND timestamp BETWEEN '2014-04-18 00:00:00' AND '2014-04-18 23:59:59')
UNION
(SELECT 'b', id, timestamp FROM table_b WHERE client_id=1 AND timestamp BETWEEN '2014-04-18 00:00:00' AND '2014-04-18 23:59:59')
ORDER BY timestamp;
Run Code Online (Sandbox Code Playgroud)
但是,您的数据也可能未完全规范化,并且table_a和table_b的公共属性应位于第三个表中.此模式称为"连接表继承".
例如:
table_common
- id
- type ('a' or 'b')
- client_id
- timestamp
- primary key: (id, type) if id is not unique.
- index: (client_id, timestamp)
table_a
- id (same value as in table_common)
...
table_b
- id (same value as in table_common)
...
Run Code Online (Sandbox Code Playgroud)
由于您现在共享一个公共索引,因此您可以执行以下操作:
SELECT id, type, timestamp FROM table_common
WHERE client_id=1 ORDER BY timestamp LIMIT 100;
Run Code Online (Sandbox Code Playgroud)
如果您需要子表中的更多字段,请在条件中使用LEFT OUTER JOIN和包含type:
SELECT * FROM table_common
LEFT OUTER JOIN table_a ON table_common.type='a' AND table_common.id=table_a.id
LEFT OUTER JOIN table_b ON table_common.type='b' AND table_common.id=table_b.id
ORDER BY timestamp LIMIT 100;
Run Code Online (Sandbox Code Playgroud)