填补Mysql查询中时间序列空白的最佳方法
Posted
技术标签:
【中文标题】填补Mysql查询中时间序列空白的最佳方法【英文标题】:Best method to fill in gaps in a time series in a Mysql query 【发布时间】:2011-11-14 18:52:50 【问题描述】:我需要填补一个mysql查询结果集的时间序列的空白。我正在测试使用包含时间序列的所有数据点的辅助表进行外部联接的选项(如该线程中所示:How to fill date gaps in MySQL?)。
我遇到的问题是,添加此连接会显着增加查询响应时间(从 1 秒以下缩短到 90 秒)。
这是原始查询:
select date_format(fact_data7.date_collected,'%Y-%m') as date_col
, date_format(fact_data7.date_collected,'%d-%H:%i:%s') as time_col
, fact_data7.batch_id,fact_data7.value as fdvalue,entities.ticker as ticker
, date_format(fact_data7.date_collected,'%Y-%m-%d') as date_col2
, date_format(fact_data7.date_collected,'%Y') as year
from fact_data7
JOIN entities on fact_data7.entity_id=entities.id
where (1=1)
AND ((entities.id= 963
AND fact_data7.metric_id=1
))
AND date_format(fact_data7.date_collected,'%Y-%m') > '2008-01-01'
order by date_col asc
这是添加了辅助表 (month_fill) 外连接的查询:
select date_format(month_fill.date,'%Y-%m') as date_col
, date_format(fact_data7.date_collected,'%d-%H:%i:%s') as time_col
, fact_data7.batch_id,fact_data7.value as fdvalue
, entities.ticker as ticker
, date_format(fact_data7.date_collected,'%Y-%m-%d') as date_col2
, date_format(fact_data7.date_collected,'%Y') as year
from fact_data7
JOIN entities
on fact_data7.entity_id=entities.id
RIGHT OUTER JOIN month_fill
on date_format(fact_data7.date_collected,'%Y-%m') = date_format(month_fill.date,'%Y-%m')
where (1=1)
AND (
(entities.id= 963 AND fact_data7.metric_id=1)
OR (entities.id is null and fact_data7.metric_id is null)
)
AND date_format(month_fill.date,'%Y-%m') > '2008-01-01'
order by date_col asc
我可以重组查询以提高性能是否有替代解决方案来实现我正在寻找的结果?
11/15 更新:
这是第一个查询的 EXPLAIN 输出:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE entities const PRIMARY PRIMARY 4 const 1 Using filesort
1 SIMPLE fact_data7 ALL NULL NULL NULL NULL 230636 Using where
这是第二个查询的 EXPLAIN 输出:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE month_fill index NULL date 8 NULL 204 Using where; Using index; Using temporary; Using filesort
1 SIMPLE fact_data7 ALL NULL NULL NULL NULL 230636 Using where
1 SIMPLE entities eq_ref PRIMARY PRIMARY 4 findata.fact_data7.entity_id 1 Using where
【问题讨论】:
EXPLAIN的结果在哪里? 将其添加到最初的问题中。 【参考方案1】:甚至不考虑重构查询,我首先会在日期列 fact_data7.data_collected 和 month_fill.date 上添加索引。您正在执行的范围查询 ">" 正在减慢进程,从理论上讲,添加索引应该会提高性能,但您需要足够的记录,否则管理索引只会因为管理索引所涉及的处理而减慢。
查看这个mysql文档http://dev.mysql.com/doc/refman/5.0/en/optimization-indexes.html
我不确定你想要达到什么目的,但你可以尝试使用 mysql 的ifnull(value1,value2)
函数来实现。您的查询可能类似于以下内容:
select ifnull(date_format(fact_data7.date_collected,'%Y-%m'),date_format(month_fill.date,'%Y-%m')) as date_col,
date_format(fact_data7.date_collected,'%d-%H:%i:%s') as time_col,
fact_data7.batch_id,
fact_data7.value as fdvalue,
entities.ticker as ticker,
date_format(fact_data7.date_collected,'%Y-%m-%d') as date_col2 ,
date_format(fact_data7.date_collected,'%Y') as year
from fact_data7 , month_fill
JOIN entities on fact_data7.entity_id=entities.id
where ((entities.id= 963 AND fact_data7.metric_id=1) OR (entities.id is null and fact_data7.metric_id is null))
and date_format(fact_data7.date_collected,'%Y-%m') = date_format(month_fill.date,'%Y-%m') --you will need a condition similar to this depends on the data
AND date_format(fact_data7.date_collected,'%Y-%m')>'2008-01-01'
order by date_col asc
【讨论】:
我已经在 fact_data7 中的 date_collected 上有一个索引。我刚刚在帮助表中的日期字段上添加了一个索引,但该表相对较小(240 行 vs ~20000 in fact_data7)并且索引对性能没有任何影响。 你能用第二个连接计算第二个查询吗?我怀疑您返回的记录可能是预期的 240 倍? 它不是在做笛卡尔积,如果那是你所怀疑的。第一个查询返回 18958 行,第二个查询返回 19055 行(填空月份)。【参考方案2】:我认为值得尝试重写 where
以便不使用 date_format(date_collected)
。你说你在这个字段上有一个索引,但它从未使用过(字段是函数的参数,
MySQL 不支持基于函数的索引)
【讨论】:
以上是关于填补Mysql查询中时间序列空白的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章