最近提到一个需求。需要记录app用户在使用app中的移动轨迹,即坐标值。每分钟上传一次XY坐标,有点类似跑步软件的描线轨迹。
不考虑app如何获取,反正api只要接受到坐标数据 就记录下来保存到数据库。接口接收3个参数X,Y,uid
1,建个新库。test 无论你是云DB还是同服务器下都可以
1 'DB_CONFIG2'=>array( 2 'db_type'=>'mysql', 3 'db_user'=>'root', 4 'db_pwd'=>'', 5 'db_host'=>'localhost', 6 'db_port'=>'3306', 7 'db_name'=>'test', 8 ),
2,建一个保存自增主键ID的表
1 CREATE TABLE `create_id` ( 2 `id` bigint(20) NOT NULL AUTO_INCREMENT, 3 PRIMARY KEY (`id`) 4 ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='自增ID表';
3,附上主要代码
1 class TestAction extends Action { 2 3 function _initialize(){ 4 $this->db_2= M()->db(2,"DB_CONFIG2"); 5 $this->union_sql="CREATE TABLE IF NOT EXISTS `%s` ( 6 `id` int(11) NOT NULL, 7 `longitude` decimal(10,6) NOT NULL COMMENT '经度', 8 `latitude` decimal(10,6) NOT NULL COMMENT '纬度', 9 `addtime` int(11) NOT NULL COMMENT '添加时间', 10 `uid` int(11) NOT NULL COMMENT '用户ID', 11 PRIMARY KEY (`id`) 12 ) ENGINE=MRG_MyISAM DEFAULT CHARSET=utf8 INSERT_METHOD=LAST UNION=(`%s`);"; 13 $this->num_sql="CREATE TABLE IF NOT EXISTS `%s` ( 14 `id` int(11) NOT NULL, 15 `longitude` decimal(10,6) NOT NULL COMMENT '经度', 16 `latitude` decimal(10,6) NOT NULL COMMENT '纬度', 17 `addtime` int(11) NOT NULL COMMENT '添加时间', 18 `uid` int(11) NOT NULL COMMENT '用户ID', 19 PRIMARY KEY (`id`) 20 ) ENGINE=MyISAM DEFAULT CHARSET=utf8;"; 21 22 } 23 24 public function index() { 25 $uid=228; 26 $id = 10000099; 27 //$id = $this->create_id();//生成自增ID 28 //$uid=trim($_GET['uid']); 29 $union_table_name="point_".$uid;//总表表名 30 //新增记录分配分表名 31 $num_table_name= $this->get_data_table($uid,$id); 32 //分表名拼接 33 $union_table_string=$this->get_union_string($uid,$id); 34 //分表语句 35 $num_sql=sprintf($this->num_sql,$num_table_name); 36 $this->execute($num_sql);//新建分表 37 //总表语句 38 $union_sql=sprintf($this->union_sql,$union_table_name,$union_table_string); 39 echo $union_sql; 40 $re1= $this->execute($union_sql);//创建总表 41 echo ($this->db_2->getDbError()); 42 43 //新增记录 44 $re=$this->execute("INSERT INTO $num_table_name (`id`, `longitude`, `latitude`, `addtime`, `uid`) VALUES ('$id', '1111.000000', '2222.000000', '22222', '$uid');"); 45 46 if($re){ 47 echo json_encode(array("status"=>1,"info"=>true)); 48 }else{ 49 echo json_encode(array("status"=>0,"info"=>false)); 50 } 51 52 53 } 54 55 56 /** 57 * 创建一个自增主键 58 * @return int 59 */ 60 private function create_id(){ 61 $sql = "insert into create_id (id) values('')"; 62 $this->db_2->execute($sql); 63 return $this->db_2->getLastInsID(); 64 } 65 66 /** 67 * 获得表名 68 * @return string 69 */ 70 private function get_data_table($uid=null,$id=null){ 71 if(empty($uid)||empty($id)){ 72 return false; 73 } 74 return 'point_'.$uid.'_'.$this->get_table_num($id); 75 } 76 77 /** 78 * 获得记录所在表序号 79 * @param $id 记录ID 80 * @param $max 表最大记录数 81 * @return int 82 */ 83 private function get_table_num($id,$max=10000000){ 84 $num = ($id<$max) ? 1 : intval($id/$max); //整除取整,默认1 85 $add = ($id%$max)>0 && ($id>$max) ?1:0;//有余数,序号加1 86 return $num+$add; 87 } 88 89 /** 90 * 判断表是否存在 91 */ 92 private function table_exit_create($table=null){ 93 return $this->db_2->query("show tables like '%{$table}%'"); 94 // return $this->db_2->query("desc {$table}"); 95 } 96 97 98 /** 99 * 建表 100 * @return bool 101 */ 102 private function execute($sql){ 103 return $this->db_2->execute($sql); 104 } 105 106 /** 107 * 生成拼接分表名字符串 108 * @param type $uid 109 * @param type $id 110 * @return string 111 */ 112 private function get_union_string($uid=null,$id=null){ 113 $res = $this->table_exit_create("point_".$uid."_"); 114 if($res){ 115 if(count($res)>1){ 116 $arr=array(); 117 foreach($res as $v){ 118 $arr[]=$v["Tables_in_test (%point_".$uid."_%)"]; 119 } 120 $str= implode(',',$arr); 121 }else{ 122 $str= "point_".$uid."_".$this->get_table_num($id); 123 } 124 }else{ 125 $str= "point_".$uid."_".$this->get_table_num($id); 126 } 127 128 return $str; 129 130 131 }
4,分析
原理非常简单。
api接受到参数 -》主键表产生一个主键-》判断主键范围,分配分表名-》创建分表,并把这次接受参数插入分表(注意:所有分表的主键字段必须由主键表产生,确保唯一性)
-》创建总表(必须是ENGINE=MRG_MyISAM),把分表union关联起来,方便查询
分表必须MyISAM引擎,主键非自增
补充:1,注意完善参数验证 。UID真实性等
2,每个分表我取1千万,更大的没有测试。
参考文章:百度来的http://soft.chinabyte.com/database/72/12620572.shtml