我们公司是做手机app的,现在要统计用户的信息。已有条件:每个用户唯一ID,其属性有产品名,版本名,系统名,安装日期,国家,运营商等等。现在要按照时间的维度(日、周、月)统计每个属性下的用户量,还要支持组合式统计(比如统计2012年3月2日使用Android4.1系统的日本用户有多少)。难点在于,对于一个ID下的每个属性,都是有可能变的。比如,2月1日某用户使用的是Android4.0,但他7号刷系统刷到了4.1,那这个人在1号到7号的周统计中就只能算作4.1的用户。 我现在想到的是按天存每个用户的详细信息,每天、每周、每月都存一个总结表。但对于组合式搜索还是比较慢,望各位大神畅所欲言,给小弟一些数据库设计方面的经验。

解决方案 »

  1.   

    create table User (
    ID int unsigned not null primary key,
    UniqueID varchar(64) not null) engine=InnoDB,character set=utf8,collate=utf8_bin;
    //如上表,每一个用户以“UniqueID”表示,实际为字母和数字组成的字符串;为方便,我再给予一个整型ID,这张表就作为一个字典表,下面所有表中的ID就是这里的ID。每一个ID和UniqueID一一对应,都是唯一的(由后台程序控制)。
    create table LaunchUser (
    SummaryDate date not null,
    ID int unsigned not null,
    Version smallint unsigned not null,
    System smallint unsigned not null,
    Device smallint unsigned default 0,
    Location smallint unsigned default 0,
    Language smallint unsigned default 0,
    unique key(SummaryDate,ID)) engine=myisam,default charset=utf8
    //上表是我存储每个用户的详细信息表,以天为单位(SummaryDate),以天+ID作为唯一键,其他Version(产品版本)、System(系统名)、Device(设备型号)、Location(地域)、Language(语言)都是用户的属性,而且关键都是可能会变的。所以这张表会有大量的冗余,目前2011年年初到现在已有1亿多行。
    其次,如第一张User表类似,我为每个属性也都建了一个字典表,都以smallint来代替字符串,这里就不写出这些字典表了,同样也都是以后台程序来控制唯一性。create table Location(
    DateType tinyint unsigned not null,
    SummaryDate date not null,
    NameID smallint unsigned not null,
    LaunchUser int unsigned not null,
    NewUser int unsigned not null, 
    unique key(DateType,SummaryDate,NameID))engine=innodb,default charset=utf8;
    //这是总结表,这里以Location(地域)为例。DateType指的是日、周、月,分别以1、2、3表示,SummaryDate和上表一样,是统计日期。但如果DateType为2或3的时候,也就是周或月统计的时候,SummaryDate的值取该周或该月的最后一天。NameID指的就是具体的地域,如1表示中国,2表示日本,3表示美国等等,这里没有用ID这个名字是为了和用户ID相区别。如上面所述,每个属性都有一个字典表,这里没有写出。DateType+SummaryDate+NameID唯一确定一条记录。后面的LaunchUser和NewUser分别表示启动用户数和新用户数,由后台程序算出。这样,如果有这样一条需求“2012-01-01到2012-01-31这一个月中国启动用户数分别是多少”,就可以写“select LaunchUser from Location where DateType=1 and SummaryDate>='2012-01-01' and SummaryDate<='2012-01-31' and NameID=1”。所以,每个属性(Location、Language等等)都有两个表,一个总结表,一个字典表,都是隔开的,总结表里面的数值都是后台程序算出的。如果有组合式的搜索需求,我就只能从最大的那张表,就是LaunchUser表中去获取数据,比较慢。而且,现在有新的时间需求,比如要一个季度、一年的数据。。那就更慢了。我当然可以加入新的DateType,比如4表季度,5表示年。但这里我先提一下我的后台程序的编写,为了统计准确,按日、周、月统计这三块在程序中都是独立开的,现在要统计季度或者年,对后台程序也是个挑战,这是题外话了。下班了,由于本人家庭没有网络,只能明天回帖了,不好意思。还望各位先看看,如有疑问我明天解答。非常感谢!
      

  2.   

    LaunchUser :
    SummaryDate ID 属性ID 属性种类ID属性对照表:
    属性ID  属性名称
    2       Device
    1       Location属性种类对照表:
    属性ID 属性种类ID  属性名称
    1      1          ....
    1      2          ....
      

  3.   

    这些字段 System Device Location Language