您的位置:永利集团登录网址 > 计算机教学 > 抛砖引玉:使用二进制位操作,解决铁道部火车

抛砖引玉:使用二进制位操作,解决铁道部火车

2019-12-09 07:28

删除特定影响因素(字段列)下的重复记录(MySQL),影响因素mysql

;CREATE TABLE TabTest
(
    `id` INT(11) NOT NULL AUTO_INCREMENT     
    ,`factorA` VARCHAR(255) NOT NULL DEFAULT ' '
    ,`factorB` VARCHAR(255) NOT NULL DEFAULT ' '
    ,`factorC` DECIMAL(10,2) NOT NULL DEFAULT 0
    ,`remark` VARCHAR(255) NOT NULL DEFAULT ' '
    , PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 COMMENT='';

INSERT INTO TabTest(factorA, factorB, factorC, remark)
SELECT 'A1', 'B1', 0.5, '1..'
UNION ALL SELECT 'A1', 'B1', 0.5, '2..'
UNION ALL SELECT 'A2', 'B2', 0.5, '3..'
UNION ALL SELECT 'A2', 'B2', 1.5, '4..'
UNION ALL SELECT 'A2', 'B2', 0.5, '5..'

;SELECT * FROM TabTest;

-- 方案一
;DELETE FROM TabTest WHERE id NOT IN ( SELECT * FROM ( SELECT id FROM TabTest GROUP BY factorA, factorB, factorC ) b );

-- 方案二
DELETE FROM TabTest WHERE id IN 
(
    -- MySQL Error 1093 – Can't specify target table for update in FROM clause
    SELECT b.id FROM 
    (
        SELECT tOuter.`id` FROM TabTest tOuter 
        INNER JOIN 
        (
            SELECT tInner.id, tInner.factorA, tInner.factorB, tInner.factorC
            FROM TabTest tInner
            GROUP BY tInner.factorA, tInner.factorB, tInner.factorC
            HAVING COUNT(1) > 1
        ) a
        ON tOuter.`factorA` = a.`factorA`
        AND tOuter.`factorB` = a.`factorB`
        AND tOuter.`factorC` = a.`factorC`
        WHERE tOuter.`id` <> a.`id`
    )b
)

方案一: 数据量小时, 比较便捷

方案二: 数据量大时使用, 第一个方案在70万数据下试过, 5分钟出不来结果, 放弃, 使用第二种方案, 秒完.

; CREATE TABLE TabTest( `id` INT ( 11 ) NOT NULL AUTO_INCREMENT ,`factorA` VARCHAR ( 255 ) NOT...

这是之前公司的一个业务的调研测试报告,测试数据量大约是一天8640万条数据。

    又到节假日,园子里面不少高人再次对12306网站的各种问题的各种分析和提出各种解决方案,我也看了这些讨论文章,出于也是一个买票难的“码农”,也来献计献言,把我跟其他人讨论的结果汇总发表一下,希望抛砖引玉,解决铁道部火车票的数据查询和存储问题。

定位系统数据库设计方案

 

——历史轨迹表

    现在,12306网站给人的第一感受就是购票过程网页很卡,不少人分析是由于数据库非常庞大,有复杂的查询和数据传输,并着重在数据库的设计方面大作文章,却很少有人在数据存储“量”上下功夫。或许大家都说现在磁盘那么便宜,还要刻意关注数据存储量的大小么?我觉得做一个大型的系统必须关注这个问题,因为数据量决定了数据的存储方式、查询方式、处理方式等等,比如数据量太大了一般就要分表甚至分库,甚至分数据中心,数据量大了处理不过来就需要数据库做集群,还有灾备方案等等,甚至,数据量大了,还得在业务处理上做出改变,比如把过期的数据放到备用库去,当前系统只用最常用的数据。

作者:Dreamingodd

 

2012.9.5

    12306的数据肯定有很多种,这里我只讨论“车票数据”,

Version:2.2.0

它涉及的数据有:

目录

  • 车票数量、
  • 余票数量、
  • 座位号、
  • 车厢号、
  • 车次、
  • 站次、
  • 发车时间等;

1.引言4

(同样,为简化设计,我们这里假设车票都是从起点到终点的,没有考虑到中间的站到站的票。)

1.1目标 4

 

1.2范围 4

涉及的业务操作有:

2.方案描述4

  • 查询是否有票、
  • 查询余票数量、
  • 查询座位信息(是否有空位、空位位置)、
  • 更新座位信息(买票、退票);

2.1表结构 4

 

2.2不同方案的介绍 5

车票数据该如何存储呢?我跟有的朋友交流,他们说至少要设计这样的数据表:

2.2.1原方案5


2.2.2一张表5

       车票表:

2.2.3季节分区5

========================

2.2.4月份分区5

int           唯一标识  NOT NULL,

2.2.5员工分区5


2.2.6员工分表和月份分区5

int           车次号  NOT NULL,

2.2.7员工分区和月份分区5


2.2.8员工分区加索引6

datetime  发车时间  NOT NULL,

3.查询速度测试6


3.1数据描述 6

int           车厢号  NOT NULL,

3.2历史轨迹查询 6


3.2.1测试方法描述6

int            座位号  NOT NULL

3.2.2测试结果(所有测试结果单位为秒)6


3.3位置查询 7

 

3.3.1测试方法描述7

    计算下,这个表存储一行数据需要 4+4+8+4+4=24个字节

3.3.2测试结果(所有测试结果单位为秒)7

    假设一列车中的每一节车厢,最多有128个座位(实际上没有这么多,卧铺车厢座位更少)

3.4结果分析 7

    那么1节车厢的座位占据的数据量是 128 * 24=3072字节

4.插入速度测试7

    假设每列火车有20节车厢,那么车票数据共需要占用 3072 * 20=61440 字节

4.1概述 7

 

4.2测试方法描述 8

    至于全国每年会发多少趟车,一共会卖出多少张车票,由于没有准确数字,我这里就不计算了,但相信肯定是一个很大的数字,13亿人每个人每年平均都坐过一次火车吧?那么这个火车票数量还是很庞大的。

4.3测试结果(所有测试结果单位为秒) 8

 

4.4结果分析 8

    说了车票数量,我们来说说旅客买到一张票,他对一列火车中车票数据的查询情况:

5.人员分布测试(Ed.2.1)9

    对1个人而言,最低需要查询1次,最多需要查询128 * 20=2560 次,每人平均查询量= 1280次;

5.1 人员分布测试方案描述 9

    对整个列车的人而言,买完所有的票,需要查询 1280次 * (128座位 * 20节车厢) = 3276800 次(好熟悉的数字)

5.2 插入速度测试 10


5.3 查询速度测试 10

    使用数据库表的方式来存储车票数据,我们卖出所有的一趟车的车票,居然有高达300多万次查询!

5.4 结果分析 10

    而且,在国庆、春运等客流量高峰时段,这些查询次数还会更大、更密集!

5.5 解决方案 10

    分析到了这里,我们似乎已经发现了,12360的车票购买系统,最大的瓶颈,不仅仅在于数据量,还包括查询次数和查询频度!

5.6查询速度测试2 10

    问题找到了,我们就来看看如何降低数据量,降低查询次数,来作为系统优化的关键点。

5.7 结果分析2 11

 

6.定位模糊对DB的影响(Ed.2.2)12

颠覆传统的设计方案--“二进制位”车票数据查询与存储方案

6.1 方案描述 12

关键思想,就是利用二进制中的 0,1 来表示座位情况,即:

6.2 影响结果的参数描述 12

如果当前位等于0,表示空位,可以售票,如果等于1,表示无空位,票已经售出。

6.2.1移动最小距离12

 

6.2.2 超时时间12

所以,一张车票,仅需一个二进制位!

6.2.3 测试所选用的数据分析12

 

6.3 结果分析 12

 

7.总结13

假设一列车有20节车厢,每节车厢128个座位,那么仅需要 20 * (128/8)=320 字节来存储整列火车的车票信息。

 

 

1.引言

各位看官,如果有板凳、西红柿等等的,请先别乱扔,且听下文分解:)

1.1目标

之前的系统Track(轨迹)表的设计是由员工ID号生成,也就是说一千个人,一千个数据表。这使得查询位置的时候,需要从一千个不同的表中插入和查询数据。故尝试重新设计。

注意:

1.2范围

仅涉及原系统的历史轨迹查询和位置查询两个功能,以及Track表。

为讲述方便,下面会借用一些计算机语言中的某些概念,如变量申明、位操作等,但仅作为“伪代码”使用,不跟某个具体的语言相对应。)

2.方案描述

 

2.1表结构

原方案的表结构:

CREATE TABLE `track_1094` (

  `track_id` bigint(20) NOT NULL AUTO_INCREMENT,

  `trackTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,

  `x` double NOT NULL,

  `y` double NOT NULL,

  `z` double NOT NULL,

  `area` double NOT NULL,

  PRIMARY KEY (`track_id`),

  KEY `trackTime` (`trackTime`)

) ENGINE=InnoDB AUTO_INCREMENT=549207 DEFAULT CHARSET=utf8;

 

新方案的表结构:

CREATE TABLE prison_all (

  track_id bigint(20) NOT NULL,

  trackTime timestamp NOT NULL default CURRENT_TIMESTAMP,

  id int NOT NULL,

  x double default NULL,

  y double default NULL,

  z double default NULL,

  area double default NULL

)engine=archive DEFAULT CHARSET=utf8;

 

 

由于新方案主要尝试用一张表解决问题,所以加了员工的ID,相当于原方案中的MAC地址(标签),engine一开始选用的是archive,最后换回了InnoDB。

 一、方案设计

 

2.2不同方案的介绍

1,如何卖票?

假设有一个字节表示1-8号位置,卖票的时候,只需要将字节中指定位置的“位”置为1即可。
那么我们定义一个字节变量:

byte P=0x00;

卖出第一张票,那么现在的座位情况是“0000 0001”   ,变量变为 P=0x01;

卖出第二张票,那么现在的座位情况是“0000 0011”   ,变量变为 P=0x03;

卖出第三张票,那么现在的座位情况是“0000 0111”   ,变量变为 P=0x07;

卖出第四张票,那么现在的座位情况是“0000 1111”   ,变量变为 P=0x0F;

卖出第五张票,那么现在的座位情况是“0001 1111”   ,变量变为 P=0x1F;

卖出第六张票,那么现在的座位情况是“0011 1111”   ,变量变为 P=0x3F;

卖出第七张票,那么现在的座位情况是“0111 1111”   ,变量变为 P=0x7F;

卖出第七张票,那么现在的座位情况是“0111 1111”   ,变量变为 P=0xFF;

2.2.1原方案

Engine:Archive,简称:员工分表。设计了一千个员工,id范围(0-1000)。得到一千张表。

2,如何标记车票已经卖出?

现在的问题是,卖出一张票的时候,怎么将变量指定位置的数置为1?
其实,可以对位进行“OR”操作,
例如当卖出第五张票的时候,可以这样执行:

 

P5= 0x0F OR 0x10 = 0x1F

 

其中,0x10 就是 “0001 0000”

同理,
例如当卖出第六张票的时候,可以这样执行:

P6= 0x1F OR 0x20 = 0x3F

... ...

 

2.2.2一张表

Engine:Archive,用于测试时的比较。所有的数据在一张表中,没有其他处理。

3,如何查询有空位?

假设我们这个变量P是严格保护的,没有外在因素作用于它,那么很简单,当 P<>0xFF ,那么肯定还有座位。

 

2.2.3季节分区

Engine:Archive,一张表,四个分区,按照时间。

4,如何查询特定位置是否还有空位(有票)?

现在大部分车都需要买票的时候挑选座位,假设以后某列车很特别,需要挑选座位的功能,我们也可以简单实现:

例如,查询2号位置是否有座:
  假设2号位置有座,那么我们可以这样表示(假设其它位置都有人在坐):P=“1111 1101”,那么进行下面的运算:
  P XOR 0x02 = "0000 0000" = 0

  假设2号位置无座,那么我们可以这样表示(假设其它位置都有人在坐):P=“1111 1111”,那么进行下面的运算:
  P XOR 0x02 = "0000 0000" = 1

  同理,要查询3号位置是否有座,那么只需要
  P XOR 0x4
  即可,如果结果=1,表示无座,可以卖出一张票,反之,则当前位置不可以卖出车票。

 

2.2.4月份分区

Engine:Archive,一张表,12个分区,按照时间。

5,如何计算座位号?

我们规定,在一列车厢里面,有 8 * N 个座位,那么我们用一个数组来存储该列车厢中所有的座位:

byte[] B=byte[N];

显然,1-8号位置,是 B[0],9-16号,是B[1]... 以此类推,便可计算出所有的所有的座位号了。

 

2.2.5员工分区

Engine:Archive,一张表,按照员工ID使用HASH分区法分为100个分区。

6,如何退票

  退票,就是将制定座位号的数的特定位置重新置回二进制位的“0”,具体过程,相信看了前面的说明,不用我再说了吧?

 

2.2.6员工分表和月份分区

Engine:Archive,先按员工数分为1000张表,再按照月份将每个表分为12个分区。1000*12=12000各分区。

 二、方案比较

 

2.2.7员工分区和月份分区

Engine:Archive,一张表,先按月份分为12个分区,再按照员工ID号将每个月份分区分为80个次分区,形成共960个分区。

 

1,查询某趟车是否还有空位,需要查询多少次?

 

     假设一列火车的座位数据为 byte[] T = byte[320], 那么只需要取 T[n]<>0xFF (n>=1,n<=320),最多总共只需要执行 320 次查询,平均算160次;

    对整个列车的人而言,买完所有的票,需要查询 160次 * (128座位 * 20节车厢) = 409600 次,

    当前方案的查询次数是传统查询方案的 1/8 。 

 

2.2.8员工分区加索引

Engine:InnoDB,一张表,按照员工ID使用HASH分区法分为500个分区,为id和tracktime加上复合索引,因为,两种查询都会用到这两列值。

2,查询某趟车是否还有空位,查询的数据量是多少?

 

    假设对某次列车的全部火车票的数据进行遍历,那么查询处理的数据量仅为 320字节!

    那么查询所需要的IO吞吐量,将是原有方案的 320 / 61440 = 1 /192 。

 

3.查询速度测试

3,查询某趟车是否还有空位,查询效率提升了多少?

 

    假设效率 E 跟查询次数 C 和数据量D成某个函数关系 E=C * D ,那么原有方案的效率比当前方案的效率相当于 1/ 1280

    看到了吗?现有方案,在查询效率上,有“数量级”的性能提升,是原有方案的1536倍!

 

3.1数据描述

    将一亿条数据分别插入8种方案,以供查询。数据时间范围1年、任意天数、任意小时数、20分钟、0秒。即并不完全是随机时间。这样做是希望一亿条数据能基本覆盖所有可能出现的时间值。每人1亿/1000=10万条,时间可能数:365*24*20=17万。这个方案并不合理,但最开始的时候造出的数据只能沿用了。否则再插一遍几亿的数据太浪费时间。

4,其它操作的效率?

 

    查询指定位置的车票是否已经买车、将指定座位号的车票卖出或者退票,这些都需要遍历整个车的车票数据,带来查询次数和查询的数据量问题,其实这个效率影响跟第3个问题应该差不多,也会有“数量级”的性能提升,具体的效率就由大家去计算了。

 

3.2历史轨迹查询

三、方案的并发与效率问题

 本文发出后,下面回复的朋友一致指出了“锁”的问题,因为在传统的高并发程序中,“锁”似乎是必不可少的,必须用锁来保证数据的一致性。所以,这里补充一节内容进行说明。

另外,我还需要特别说明的是,我的方案不是一个数据库里面的数据存储与查询方案,这是一个完全基于内存数据计算的方案,因为它的数据量足够小,全部的车票数据放到内存中也是没有问题的。

 

3.2.1测试方法描述

查询一定时间段内某名员工的track数据。

查询语句:

Select * from table_name where id = ?  and trackTime < ?  and trackTime > ? ;

1,不需要锁的“并发”方案

当有一个线程准备进行对车票锁定的时候(在火车售票过程中,只要查询到有票就会锁定该票,以便顺利完成下面的售票过程),实质上是将当前查询到的字节中指定的位置置为“1”,出票的时候是确认该操作,而放弃购票的话将该位置重新置为“0”即可。

 那么如何标记当前位置(字节)有线程正在使用呢?

假设当前位置的序号是S,数据是P,如果它正被前面一个线程使用,那么它必定某个位置已经被置为了“1”,假设P当前的情况是 "0000 0011" ,   那么肯定 P〉0 ,于是新的序号S=S+1,第二个线程使用的数据为P2。

 

但这里还有一个问题,前面的这个数据P还有空位没有被填充使用完,所以,我们可以规定数据P一直被它原来使用的线程持有,直到填满,P=0xFF 为止。

由此,我们推导出第二个重要的方案

 

3.2.2测试结果(所有测试结果单位为秒)

亿级别历史轨迹查询(s)

1时

1天

5天

10天

1月

2月

1

员工分表(原方案)

0.4

0.4

0.5

0.6

0.7

2.9

2

就一张表

280

没测

没测

没测

没测

没测

3

季节分区

250

没测

没测

没测

没测

没测

4

月份分区

225

没测

没测

没测

没测

没测

5

员工分区

2.1

2.3

2.4

2.4

2.5

2.7

6

员工分表+月份分区

Fail

Fail

Fail

Fail

Fail

Fail

7

员工+月份分区

530

没测

没测

没测

没测

没测

8

员工分区加索引

0.02

0.05

0.16

0.2

0.7

0.9

 

2,批量“写入”方案

由于数据P一直被它原来使用的线程持有,所以这个线程完全可以等待下一个购票人来使用。注意这里的区别,是等待另外一个人,而不是另外一个线程来争抢。于是,我们便完成了批量写入购票信息的方案。写入之后,该线程再释放,获得另外一个新的数据序号S,进行新的处理。注意,这里的序号S其实是我们车厢车票数组的下标,它本身是不需要进行锁定然后加一的,它仅仅是一个存放在“寄存器”的循环变量。

 

3.3位置查询

3,内存数据高效加载技术

CPU取数据最快的地方是L1 Cache,通常计算机它的大小是 64字节,我们惊奇的发现,我们一节车厢的128个字节,仅需要加载2次就可以处理完,如果我们的CPU有2个核,那么我们的每个CPU可以同时分别加载64个字节,然后分别进行计算处理。

如果采用1个CPU只运行1个线程的处理方案,128字节的车票数据分别在2个物理线程(CPU核)中处理,这2个线程根本无需考虑锁的问题。

该理论可能令很多人难以理解,因为它涉及了真正的物理上的计算机知识,这里不做更多说明,详细内容,请参看著名的LMAX开源高性能架构Disruptor的 

Disruptor 全解析(6):为什么它这么快 (二) - 神奇的 cacheline 补齐

实际上,这里的第1点和第2点,原理也比较类似Disruptor的RingBuffer技术,详细内容可以参考

Disruptor 全解析(6):为什么它这么快 (二) - 神奇的 cacheline 补齐

 

 

3.3.1测试方法描述

查询一定人群在特定时间点的位置。

查询语句:

Select  * from table_name where id < ? and trackTime = ? ;

四、方案总结与设想

  通过前面的分析,我们发现采用二进制位进行车票数据的查询和存储,能够极大地提升整个系统的操作效率,降低存储量,降低查询次数,而这正是现在12306最需要优化的关键点。

    由于该方案精巧的设计,使得整个12306网站不必依赖于庞大的存储设备和计算设备,以现在服务器的本身配置的超大内存和磁盘存储空间以及CPU计算能力,运行该方案应该很轻松。如果再使用 Disruptor 这样的架构(号称每秒处理600万订单),那么12306网站的问题,是有可能得到解决的。下面是它的架构图:

图片 1

附录:

 

3.3.2测试结果(所有测试结果单位为秒)

亿级别位置查询

1个人

10人

100人

所有人

1

员工分表(原方案)

0.3

4

45

477

5

员工分区

3.3

291

291

295

7

员工+月份分区

0.5

38

没测

没测

8

员工分区加索引

0.02

9

9.5

9

3.4结果分析

由于方案3(季节分区)和方案4(月份分区)在历史轨迹的第一次测试中就超过3分钟所以在接下来的测试中被放弃,方案6(员工分表+月份分区,1000*12=12000个分区)的方案在插入数据时在第500分区处崩溃,即使换成员工分表+季节分区(1000*4=4000个分区)也在第1500分区处崩溃,所以这个方案也被放弃。方案7员工分区的表现还可以,但几乎每个测试所用的时间都在原方案的5-10倍,所以一样放弃。

由于Archive引擎不支持索引,所以最后一个方案的引擎改用InnoDB——员工分区加索引,这个方案在测试中表现良好,在与原方案的比较中基本完胜。尤其是在所有人的位置查询中比原方案快近500倍,但是加索引之后的插入效率会成为问题。所以接下来做了这个方案的插入速度测试。

The LMAX Architecture

  

 

4.插入速度测试

4.1概述

原方案的插入是向1000张表中定时插入数据,而且是一条插一次,并且不停地换表,所以插入效率是很低的,以上任意方案(除分表+分区),效率都应该是要高过原方案的。但大数据量的表加索引时插入效率也很低。所以还是做了这个测试。

4.2测试方法描述

前提:表中已有7500万条数据,随机生成定量的Track对象,保存在List中,向方案8——员工分区加索引的表中插入数据。插入方法两种:一种是一条一条地插入,另一种是拼接一千个Track对象的数据成为一条sql语句一次性插入表中。

4.3测试结果(所有测试结果单位为秒)

员工分区加索引插入测试

1000

3000

5000

10000

批量插入

0.25

0.5

1

4

单独插入

1.9

5

9

16

4.4结果分析

拼接sql语句的效率在反复单独的十倍上下,而以3000人为基准的数据一次性插入的速度在0.5秒左右,效率上也可以接受。

 

5.人员分布测试(Ed.2.1)

5.1 人员分布测试方案描述

目前数据库方案是按天建表,原因是考虑到一个人全天在线(如养老院),一秒钟一条数据一天就是86400条,1000个人就有8千万,3000人有2亿5千万——这个数字就不一定罩得住了。当然也有一定的利用事件流和位置模糊处理减少数据量,但是这些方法还是没有经过系统的测试,也没有数据支持。

本次的测试模拟5千万的测试数据,1000人15小时为5千4百万条的数据量,分几种存储引擎,共三种方案:InnoDB、MyISAM100分区和MyISAM200分区三种。

 

表结构:

create table track_InnoDB(

tag_id bigint,

time timestamp,

x double,

y double,

z double,

area int,

status int(1),

alarm int(2),

index(tag_id,time)

)engine=InnoDB DEFAULT CHARSET=utf8

partition by hash(tag_id)

partitions 100;

 

测试目的为:三种方案的人员分布查询速度。

查询语句:

一分钟:

select max(time),x,y,tag_id from track_2012_12_13  

where tag_id in (?,?,?...) and time>='2013-01-01 11:00:00'

and time<'2012-01-01 11:01:00' group by tag_id

一小时:

select max(time),x,y,tag_id from track_2012_12_13  

where tag_id in (?,?,?...) and time>='2013-01-01 11:00:00'

and time<'2012-01-01 12:00:00' group by tag_id

5.2 插入速度测试

插入速度测试

5400万

1000计算

1亿计算

1亿大小

MyISAM引擎100分区

26分钟

0.029秒

48分钟

 

MyISAM引擎200分区

30分钟

0.033秒

55分钟

 

InnoDB100分区

79分钟

0.079秒

146分钟

 

 

5.3 查询速度测试

人员分布查询速度测试
(单位秒)

1分钟的60条数据筛选100人的100条数据

1分钟的60条数据筛选50人的50条数据

1分钟的60条数据筛选25人的25条数据

一小时的3600条数据筛选100人的100条数据

一小时的3600条数据筛选50人的50条数据

一小时的3600条数据筛选25人的25条数据

MyISAM引擎100分区

4.1

1.8

0.5

4.4

3.4

1.6

MyISAM引擎200分区

2.6

1.3

0.9

3.2

1.8

8.4

InnoDB100分区

4.8

1

0.5

5.4

3

1.1

 

5.4 结果分析

插入测试的结果证明MyISAM引擎的插入速度要好于InnoDB,但InnoDB的效率也不是不能接受,因为在项目中一次性缓存插入数据库2000条左右,1秒钟还过得去。

查询效率的问题几乎宣告了方案的失败,查人员分布理应是全部1000人的查询,由于效率太低才使用100人分批查找,但是100人4秒的效率根本无法接受。

还需再想办法。

5.5 解决方案

在华为应先生的建议下,将人员分布和历史轨迹两个业务分开,人员分布的表定位每人一分钟一次数据,这样一天的数据量为3000*24*60=432万。

 

5.6查询速度测试2

结果:16ms

5.7 结果分析2

显而易见,可以接受的结果。

问题被解决。

 

6.定位模糊对DB的影响(Ed.2.2)

6.1 方案描述

定位模糊时JAVA端对历史轨迹插入数据库的数据进行的筛选工作,主要作用在于减少数据量、减少对硬盘存储空间的要求、减轻数据库查询的压力。它可以限定一个人的移动达到一定距离才算做移动,而不算做移动的数据大部分不插入数据库,但同时在JAVA业务超时的范围内,插入一次停留的数据。具体见如下“参数描述”的超时时间。

6.2 影响结果的参数描述

6.2.1移动最小距离

移动超过多少像素算作是移动一次,移动的数据是必须插入数据库的,这个距离应该是测试不会出现穿墙等异常情况后的最大距离。

6.2.2 超时时间

超时时间是停留数据插入间隔的最小范围,如超时时间为30秒,那么在超时时间内没有移动事件的话,将在30秒内插入一次停留的数据。

6.2.3 测试所选用的数据分析

超时时间30秒,模拟移动的工具每次移动20px,以监狱版本业务的全天在线和很少移动为模型,设置最小移动距离为100px。1000人在线测试:

6.3 结果分析

 

 

一天的数据量

一天数据大小

一年数据大小

没有应用定位模糊的结果

8640万条

8G

3TB以上

应用了定位模糊的结果

350万条

388MB

292GB

 

数据量减少了24倍,当然这是比较理想的情况,1000人一年的数据量292GB。

 

7.总结

经过测试和综合平定方案8——员工分区加索引的方案查询效率最佳,但是插入数据最好在缓存中存储list,拼接成sql语句后一次性插入多条数据,才能使插入效率达到可接受的程度。

 

备注:可能查询时mac放在前面有助于提高查询效率。

 

本文由永利集团登录网址发布于计算机教学,转载请注明出处:抛砖引玉:使用二进制位操作,解决铁道部火车

关键词: