透视表的最佳方法是什么?

时间:2013-08-02 14:41:55

标签: mysql pivot-table

我有一张看起来像这样的表:

users_data_points:

id | users_id | data_types_id | value | events_id | time_inserted

data_type_id映射到某些任意内容,如“名称”或“地址”或其他数千种数据类型。

因此,对于任何单个用户,我可以在此表中包含N行。

这些行有数百万。

直接根据event_id从此表中进行选择非常快,并生成一个很长的项目列表,其中每个用户由一些行表示,每行包含一个数据点。

但是,当我需要将每个用户及其数据的某个子集的结果拉入INDIVIDUAL行时,我通常会使用子选择,现在这个过程会降低到冰冷的速度。

我的查询看起来像这样:

select users_id as uid,
events_id as eid,
(select `value` from users_data_points where users_id = uid and events_id = eid and data_type_id = 3 limit 1) as 'firstName,
        -- ... however many more of these subselects I need here
        from users_data_points where events_id = 500 and date(time_inserted) between '2013-01-01' and date(now())

我完全乐于接受能够以更有效的方式产生这种结果的任何替代解决方案。在生产中,我实际上只是抓取原始行,然后在Node中将它们一起哈希映射。这比SQL中的子选择快几个数量级,但如果有更好的方法来利用mySQL来执行此任务,我更倾向于不以这种方式拆分工作。

我完全对临时表或视图或派生表或任何其他可能有用的表开放,但我尝试的所有内容实际上都比上述解决方案更慢。

1 个答案:

答案 0 :(得分:0)

我完全赞同G-Nugget的评论。数据库并不能很好地格式化数据,但是,只是为了它,你可以做到

select users_id as uid,
events_id as eid,
max(case when data_type = 3 then `value` end) as first_name,
...
from users_data_points 
where events_id = 500 
and date(time_inserted) between '2013-01-01' and date(now())
group by users_id

如果选择min()或max(),则聚合函数无关紧要。使用case...when s(没有group by和aggregate函数),你会得到像

这样的东西
user_id   |   first_name   |   last_name   |   ...
1             john             null            null
1             null             jack            null
1             null             null            whatever

使用group by和aggregate函数,你可以在一行中得到它,瞧,你的枢轴没有子查询。这应该比你现在的速度快几倍,你仍然可以获得更多的性能在应用层上转动你的数据。