精华内容
下载资源
问答
  • 统计函数与分组查询

    千次阅读 2016-09-16 11:54:08
    1、分组统计查询1.1 统计函数(分组函数) 在之前学习过一个COUNT()函数,此函数的功能是用于统计一张表中的数据量,那么实际上这就属于一种统计函数,在SQL语法中,定义了五个常用的统计函数:COUNT()、SUM()、AVG...

    1、分组统计查询

    1.1 统计函数(分组函数)

      在之前学习过一个COUNT()函数,此函数的功能是用于统计一张表中的数据量,那么实际上这就属于一种统计函数,在SQL语法中,定义了五个常用的统计函数:COUNT()、SUM()、AVG()、MAX()、MIN()。

    范例:要求查询出公司总人数、每月支付的总工资、以及公司的平均工资、最高工资、最低工资。

    SELECT COUNT(*),SUM(sal),AVG(sal),MAX(sal),MIN(sal) FROM emp;

    范例:求出公司雇佣雇员之中,最早和最晚的雇佣日期。

    SELECT MIN(hiredate),MAX(hiredate) FROM emp;

      针对于以上的几个统计函数,还有一些非常重要的说明:
    说明一: 给出的五个函数之中,如果内统计的数据表之中没有任何数据存在,那么只有COUNT()函数返回数据。

    SELECT COUNT(*),SUM(sal),AVG(sal),MAX(sal),MIN(sal) FROM bonus;

      发现只有 COUNT() 函数返回了0,其他的函数返回的数据都是NULL,所以得出结论:COUNT()函数不管表中是否有内容,永远都会有一个具体的数据返回。

    说明二: 关于COUNT()函数使用的问题
      在现在已知使用的 COUNT() 函数采用的方式 “COUNT(*)” , 实际上也可以使用 “COUNT(字段)” 来完成,例如,现在观察如下代码。

    SELECT COUNT(*),COUNT(empno) FROM emp;

    面试题: 请说出”COUNT(*)”,”COUNT(DISTINCT 字段)”还有”COUNT(字段)”的区别?

    SELECT COUNT(*),COUNT(empno),COUNT(DISTINCT job),COUNT(comm) FROM emp;

    这里写图片描述

      COUNT(*):可以直接准确的返回表中的数据;
      COUNT():如果此字段上的内容不为NULL,其结果与COUNT()一致,如果有NULl数据,则NULL不统计;
      COUNT(DISTINCT 字段):重复的数据不统计。

    1.2、分组统计

      在学习分组统计之前,首先来思考一个问题,什么情况下可能会出现分组的问题?
      例如:生活之中,男女厕所是分开的,如果说现在要求男生和女生个一组,按照每个部门分组进行拔河比赛。所以所谓的分组一定是要求有重复,如果换回到数据库之中,就意味者列上存在重复。但是也不排除一个人一组,只是这样做的意义不大。但是分组之后就应该可以进行统计操作了,就可以使用统计函数了。
      如果要想在SQL之中实现分组,可以使用如下语法完成,增加一个 GROUP BY 子句。

    SELECT [DISTINCT] 列 [别名] | 统计函数 
    FROM 表名称 [别名], 表名称 [别名], .....
    [WHERE 条件(s)]
    [GROUP BY 分组字段]
    [ORDER BY 字段 [ASC | DESC], 字段 [ASC | DESC], ....]

    范例:要求查询出每种职位的雇佣人数、平均工资,应该按照 job 分组。

    SELECT job,COUNT(empno),AVG(sal)
    FROM emp
    GROUP BY job;

    这里写图片描述

    范例:按照部门编号分组,求出每个部门的人数,平均工资,最高及最低工资
    。应该按照deptno分组。

    SELECT deptno,COUNT(deptno),AVG(sal),MAX(sal),MIN(sal) 
    FROM emp 
    GROUP BY deptno;

    这里写图片描述

      以上实现了基本的分组操作,但是进行分组统计查询的时候也是会存在若干限制的。

    限制一:统计函数如果不结合GROUP BY 使用时,在 SELECT 子句之中, 只能够单组使用,不能够出现任何的其他字段。

    // 正确代码
    SELECT COUNT(empno) FROM emp;
    
    // 错误代码,不是单独的分组函数
    SELECT COUNT(empno),ename FROM emp;

    这里写图片描述

    限制二:如果查询之中出现了 GROUP BY 子句时,SELECT 子句只允许出现分组与统计函数,其他字段都不允许出现。

    // 正确代码
    SELECT job,COUNT(empno)
    FROM emp
    GROUP BY job;
    
    // 错误代码,不是GROUP BY 表达式
    SELECT job,COUNT(empno),ename
    FROM emp
    GROUP BY job;

    这里写图片描述

    限制三:统计函数允许嵌套,但是嵌套之后的统计查询的 SELECT 子句之中不允许再出现任何字段,包括分组字段,例如:要求查询出平均工资最高的职位中的最高工资

    // 正确代码
    SELECT MAX(AVG(sal)) 
    FROM emp
    GROUP BY job;
    
    // 错误代码,不是单组分组函数
    SELECT job,MAX(AVG(sal)) 
    FROM emp 
    GROUP BY job;

    这里写图片描述

      以上的操作都只是针对于雇员(emp)一张表的分组统计,那么如果现在有这样一个要求。

    范例:查询出每个部门的名称、雇员人数、平均工资、平均服务年限。
      · 确定所需要的数据表:
        | - dept表:部门名称;
        | - emp表:各个统计信息(empno,sal,hiredate);
      · 确定已知的关联字段:
        | - 雇员和部门关联:emp.deptno=dept.deptno
    第一步 : 转变一下操作的思路,如果现在给出的查询要求变化一下:查询出每个雇员的编号、部门名称、工资、雇佣日期。

    SELECT e.empno,d.dname,e.sal,e.hiredate 
    FROM emp e,dept d
    WHERE e.deptno=d.deptno;

    这里写图片描述

    第二步 : 分组的前提条件,列上存在重复,只要是存在重复能否都分组,什么结构叫表?包含行和列两个信息的结构都成为表,那么以上以上的查询结果是否满足一张表的形式? YES,所以现在如果把查询结果当作一张临时表,那么现在就可以直接为临时表进行分组了。

    SELECT d.dname,COUNT(e.empno),AVG(e.sal),
        AVG(MONTHS_BETWEEN(SYSDATE,e.hiredate)/12) avgyear 
    FROM emp e,dept d
    WHERE e.deptno=d.deptno
    GROUP BY d.dname;

    这里写图片描述

    第三步: 可是现在题目要求是所有部门,在dept表中有四个部门,但是现在只显示出了三个部门,所以应该考虑出现外连接。

    SELECT d.dname,COUNT(e.empno),AVG(e.sal),
        AVG(MONTHS_BETWEEN(SYSDATE,e.hiredate)/12) avgyear 
    FROM emp e,dept d
    WHERE e.deptno(+)=d.deptno
    GROUP BY d.dname;

    这里写图片描述

      所以通过以上的结论,可以发现,进行分组操作的时候并不一定非要针对实体表进行分组统计,针对于临时表(查询结果)也进行分组。

    范例: 统计出公司每个工资等级人数,平均工资
      · 确定所需要的数据表:
        | - salgtrade表:工资等级;
        | - emp表:统计信息;
      · 确定已知的关联字段:
        | - 雇员和工资等级:emp.sal BETWEEN salgrade.losal AND salgrade.hisal;

    第一步: 换一个思路,首先查询出雇员的编号,工资,工资等级。

    SELECT e.empno,e.sal,s.grade
    FROM emp e, salgrade s 
    WHERE e.sal BETWEEN s.losal AND s.hisal;

    这里写图片描述

    第二步: 针对重复的数据进行分组,此处还是临时表数据。

    SELECT COUNT(e.empno),AVG(e.sal),s.grade
    FROM emp e, salgrade s 
    WHERE e.sal BETWEEN s.losal AND s.hisal
    GROUP BY s.grade;

    这里写图片描述

      以上的所有的操作都只针对于一个单独的字段实现了分组,那么在分组操作之中,也定义了可以针对于多个字段进行分组(多个字段的内容都是重复的),此时的语法结构如下。

    SELECT [DISTINCT] 列 [别名], 列 [别名], ....| 统计函数 
    FROM 表名称 [别名], 表名称 [别名], .....
    [WHERE 条件(s)]
    [GROUP BY 分组字段, 分组字段, 分组字段, ....]
    [ORDER BY 字段 [ASC | DESC], 字段 [ASC | DESC], ....]

    范例: 查询出每个部门的编号、名称、位置、部门人数、最高工资、最低工资
      · 确定所需要的数据表:
        | - dept表:每个部门的编号,名称,位置;   
        | - emp表:统计信息;
      · 确定已知的关联字段:
        | - 雇员和部门: emp.deptno=dept.deptno;
        
    第一步: 转变思路,要求查询出每个雇员的编号,工资,部门编号,名称,位置。

    SELECT e.empno,e.sal,e.deptno,d.dname,d.loc
    FROM emp e,dept d
    WHERE e.deptno(+)=d.deptno;

    这里写图片描述

    第二步: 在以上的查询结果之中可以发现,deptno,dname,loc 三个字段都是同时重复者,所以在这种情况下,就可以使用多字段分组,而使用多字段分组的最大好处是可以在 SELECT 子句之中出现多点字段信息。

    SELECT d.deptno,d.dname,d.loc,COUNT(e.empno),AVG(e.sal)
    FROM emp e,dept d
    WHERE e.deptno(+)=d.deptno
    GROUP BY d.deptno,d.dname,d.loc;

    这里写图片描述

    范例: 要求平均工资高于1500的职位名称、雇员人数、平均工资。
    第一步: 查询出每个职位名称,雇员人数,平均工资

    SELECT job,COUNT(empno),AVG(sal)
    FROM emp
    GROUP BY job;

    这里写图片描述

    第二步: 现在要的不是全部信息,应该是对查询结果进行过滤,首相会想到使用 WHERE 子句,于是下面习惯性的编写程序。

    // 错误代码
    SELECT job,COUNT(empno),AVG(sal)
    FROM emp
    WHERE AVG(sal)>1500
    GROUP BY job;

    这里写图片描述

      发现现在在 WHERE 子句上出现了错误信息,直接告诉用户 WHERE 无法直接使用分组函数。为什么呢?
      为了解释此问题,下面思考这样的一个实际生活场景:国家每年都啊要挑选年满18周岁的青少年应征入伍,每个地区征的兵不会在本地服役,而在征兵完成之后,要统计每个部队新兵的人数,平均学历,平均身高,后来国家需要为国旗班挑选病原,那么请问,以上的若干操作,如果换到SQL之中,各个子句该如何分配呢?
       · FROM 子句:全体中国公民;
       · WHERE 子句:年满18周岁;
       · GROUP BY 子句:按照籍贯分组,以分配部队;
       · 为国旗班挑选兵源?肯定挑选平均身高185的部队进行挑选,那么此步是在 GROUP BY 之后;

    这里写图片描述

       可以发现 WHERE 子句是不可能满足分组之后的数据筛选的,于是此时有了一个新的子句: HAVING

    SELECT [DISTINCT] 列 [别名], 列 [别名], ....| 统计函数 
    FROM 表名称 [别名], 表名称 [别名], .....
    [WHERE 条件(s)]
    [GROUP BY 分组字段, 分组字段, 分组字段, ....]
    [HAVING 条件(s)]
    [ORDER BY 字段 [ASC | DESC], 字段 [ASC | DESC], ....]

    范例:利用 HAVING 进行分组之后的数据过滤

    SELECT job,COUNT(empno),AVG(sal)
    FROM emp
    HAVING AVG(sal)>1500
    GROUP BY job;

    这里写图片描述

    问题: 如何区分使用 WHERE 和 HAVING   

      · WHERE 是在 GROUP BY 子句执行之前使用,目的是针对于全部数据筛选,WHERE 不能使用统计函数;
      · HAVING 是在 GROUP BY 子句执行之后使用,目的是针对于分组后的数据筛选,HAVING 可以使用统计函数。
          
      

    1.4、练习

    1、显示非销售人员工作名称以及从从事同一工作雇员的月工资总和,并且要满足从事同一工作的雇员的月工资合计大于 $5000,输出结果按月工资的合计升序排序。

    第一步: 显示非销售人员(SALESMAN)

    SELECT *
    FROM emp
    WHERE job<>'SALESMAN';

    这里写图片描述

    第二步: 从事同一工作雇员的月工资总和,按照职位分组。

    SELECT job,sum(sal)
    FROM emp
    WHERE job<>'SALESMAN'
    GROUP BY job;

    这里写图片描述

    第三步: 针对分组后的数据再次筛选,使用HAVING 子句

    SELECT job,SUM(sal)
    FROM emp
    WHERE job<>'SALESMAN'
    GROUP BY job
    HAVING SUM(sal)>5000;

    这里写图片描述

    第四步: 输出结果按月工资的合计升序排列,使用 ORDER BY,而且 ORDER BY 是在最后执行的,可以使用 SELECT 子句之中定义的别名。

    SELECT job,SUM(sal) sum
    FROM emp
    WHERE job<>'SALESMAN'
    GROUP BY job
    HAVING SUM(sal)>5000
    ORDER BY sum ASC;

    这里写图片描述

    2、查询出所有领取佣金和不领取佣金的雇员人数,平均工资。

      首先对于习惯性的思维,应该使用 comm 字段进行分组统计。

    SELECT comm,COUNT(empno),AVG(sal)
    FROM emp
    GROUP BY comm;

    这里写图片描述
      
      但是发现,现在没有得到一个预期的结果,它是把 comm 的每个值都分组了,所以现在发现直接出答案不太可能。
      那么现在换一个思路,先不考虑分组,考虑两种查询:
       · 查询一:查询出所有领取佣金的雇员人数、平均工资、不用分组,WHERE 直接筛选

    SELECT '领取佣金' info, COUNT(empno),AVG(sal) 
    FROM emp 
    WHERE comm IS NOT NULL;

    这里写图片描述

       · 查询二:查询出所有不领取佣金的雇员人数、平均工资、不用分组,WHERE 直接筛选

    SELECT '不领取佣金' info, COUNT(empno),AVG(sal) 
    FROM emp 
    WHERE comm IS NULL;

    这里写图片描述

      现在发现以上两个查询返回的最终结构都一样,可以考虑将查询连接一下。

    SELECT '领取佣金' info, COUNT(empno),AVG(sal) 
    FROM emp 
    WHERE comm IS NOT NULL
        UNION
    SELECT '不领取佣金' info, COUNT(empno),AVG(sal) 
    FROM emp 
    WHERE comm IS NULL;

    这里写图片描述

    1.4、总结

      到现在为止,对于 SQL语法 的基本结构已经彻底了解了,再次回顾一下执行顺序:
      

    1. FROM 子句:确定数据来源,而且这个来源可能是一张表,也可能是一种查询(临时表);

    2. WHERE 子句:针对显示的数据进行条件过滤,可以编写多个条件;

    3. GROUP BY 子句:对数据进行分组,分组是针对于 WHERE 筛选之后的数据分组;

    4. HAVING 子句:针对于分组之后的数据进行再次的过滤,可以利用统计函数过滤;

    5. SELECT 子句:确定要显示的数据列或者是统计函数;

    6. ORDER BY 子句:对所有数据的显示结果进行排序,并且可以使用 SELECT 子句定义的别名。

    展开全文
  • 今天想某些班、课程的挂科人数做统计和小计,使用rollup可以很容易实现这个功能。 比如涉及的成绩(all_scores)表结构为 BH 班号 BJMC 班级名称 KCMC 课程名称 JD 绩点 其中JD为0表示挂科了。我们很...

    今天想对某些班、课程的挂科人数做统计和小计,使用rollup可以很容易实现这个功能。

    比如涉及的成绩(all_scores)表结构为

    BH 班号
    BJMC 班级名称
    KCMC 课程名称
    JD 绩点
    其中JD为0表示挂科了。我们很容易写一个分组统计来统计各个班各个课程的挂科人数

    select bjmc,
    decode(grouping(kcmc),1,'小计',kcmc) kcmc,
    sum(decode(jd,0,1,0)) fail_num
    from all_scores 
    where bh like '201255%'
    group by rollup(bjmc,kcmc)
    

    但是我想按班级小计的挂科人数逆序排列,然后再分组的显示每班每科的挂科人数。

    查了一些Oracle的SQL的资料,好像没有这个对应的函数帮我们实现这个功能,所以想了一个办法,效率不是很高,但是可以达到目的。

    WITH x AS 
             (SELECT bjmc,
                     DECODE (GROUPING (kcmc), 1, '小计', kcmc) kcmc,
                     SUM (DECODE (jd, 0, 1, 0)) fail_num,
                     GROUPING_ID (bjmc, kcmc) gp
                FROM all_scores
               WHERE bh LIKE '201255%'
               GROUP BY ROLLUP (bjmc, kcmc)
              )
      SELECT a.bjmc, a.kcmc, a.fail_num
        FROM x a, x b
       WHERE a.bjmc = b.bjmc AND b.gp = 1
    ORDER BY b.fail_num DESC,
             a.bjmc,
             a.gp DESC,
             a.kcmc

    思想很简单,使用grouping_id找出小计的行作为b表,然后对于a表中的每一行,连接到b表对应的小计数。

    然后再按我的想法,先按小计数逆序,班级名称排序。

    为了保证小计项为每个块的第一行,先优先统计行标记即可。

    展开全文
  • C# 使用DataTable的GroupBy,数据某列进行分组求和一、需求背景二、使用DataTable创建表及数据三、GroupBy数据分组求和 一、需求背景 通过Data Table创建多个行,根据MaterialID进行Group By分组Qty进行求和...

    C# 使用DataTable的GroupBy,对数据某列进行分组求和

    一、需求背景

    通过Data Table创建多个行,根据Material进行Group By分组,对Qty进行求和运算.
    原始数据

    Material TotalQTY Qty
    A 10 1
    B 20 1
    B 20 2
    A 10 3

    要获得的数据

    Material TotalQTY Qty
    A 10 4
    B 20 3

    实际上要执行该SQL语句:
    select Material ,TotalQTY,sum(Qty) from tableName group by Material ,TotalQTY ;
    由于该表是有前台创建的,DB中没有该表信息所以不能使用SQL语句,我采用的Linq语句实现的对Material ,TotalQTY的分组求和。

    二、使用DataTable创建表及数据

    //1、新建表
    private  DataTable dtResult = new DataTable();
    
    //2、表中添加列
     dtResult.Columns.Add("Material", typeof(string));
     dtResult.Columns.Add("TotalQTY", Type.GetType("System.Decimal"));
     dtResult.Columns.Add("QTY", Type.GetType("System.Decimal"));
     
    //3、初始化行并添加数据
    DataRow row = dtResult.NewRow();
    row["Material"] = "Material_A";
    row["TotalQTY"] = "100";
    row["QTY"] = "5";
    
    //4、表中添加行
    dtResult.Rows.Add(row);
    

    通过以上的代码实现原始数据

    Material TotalQTY Qty
    A 10 1
    B 20 1
    B 20 2
    A 10 3

    三、GroupBy对数据分组求和

    采用Linq语句对数据进行分组,通过创建新的DataTable达到分组求和的目的。

     DataTable dtGroupBy = dtResult.AsEnumerable().GroupBy(r => new { Material= r["Material"], TotalQTY= r["TotalQTY"]}).Select(
                        g =>{
                            var row = dtResult.NewRow();
    
                            row["Material"] = g.Key.Material;
                            row["TotalQTY"] = g.Key.TotalQTY;
                            row["QTY"] = g.Sum(r => (decimal)r["QTY"]);
                            return row;
                        }).CopyToDataTable();
    

    dtGroupBy就是要获得的数据

    Material TotalQTY Qty
    A 10 4
    B 20 3
    展开全文
  • 最近收到很多邮件咨询各种... 由于最近写了几篇关于TCP拥塞控制的文章,就有人咨询我关于NCL,New Vegas,BBR等相关的问题,其实我知道他们的目的,不外乎两种原因,要么是自己想学习一下原理但可能遇到了看不懂的地
    最近收到很多邮件咨询各种问题,一般而言我能回答的就都回答了,我自有自知之明,绝不是什么大牛,然而也并不是菜鸟,所以说不管什么问题,我不一定能完美回答,但却也不是一点都不懂,因此我会尝试着去作答。
            由于最近写了几篇关于TCP拥塞控制的文章,就有人咨询我关于NCL,New Vegas,BBR等相关的问题,其实我知道他们的目的,不外乎两种原因,要么是自己想学习一下原理但可能遇到了看不懂的地方,前来询问,要么就是想自私的加速自己的TCP连接。对于前者,我非常乐意一起探讨,但对于后者,我只能回答“我也不知道”。其实,事实上我真的不知道如何给TCP加速,我唯一知道的就是,老老实实遵循现有的TCP逻辑,毕竟它们已经经过了各种环境的测试并被认为是合理的。对于如何去抢别人的带宽,我对这件事是非常非常反感的。因此我打算利用几乎一个通宵写下本文,意在告诉大家拥塞到底是怎么发生的,以及为什么拥塞是必然发生的,如果你真的理解了,你也就想通了为什么不要去抢别人的带宽,因为你做不到。
            本文比较长,但是却比较轻松,科普性质的,没有任何理论基础的人都应该可以看懂,中间加了分割线作为休息和思考的界限。我先从微信朋友圈刷屏开始。

    刷屏 & BufferBloat the fucking

    网络拥塞的原因,其实很简单。
            为什么网络会拥塞,答案其实是一个很简单的常识。我再一次以身试法站在一个殉道者的立场上来解释为什么网络会拥塞。我会告诉你们,在另一个网络,制造网络拥塞的那个人,就是我!
            然后你们就会理解到底什么是Buffer Bloat,最终你们会理解本文下面的部分以及BBR算法的核心理念。
            我不再用交通拥堵来解释网络拥塞,因为首先大家都这么解释,其次很多人对此早已麻木,毕竟就算堵在路上,不是还可以刷朋友圈逛淘宝么??所以,我尝试用微信朋友圈来解释网络拥塞,如果你想理解的更深刻,请加我为好友并且在彻底理解Buffer Bloat之前,不要屏蔽我,等你彻底理解了,删除我,删除之前,记得给个红包,5元即可!好吧,让我们上路。
            如今大家都玩微信和微博,特别是微信。玩微信的几乎都有刷朋友圈的习惯。你们碰到过有人刷屏吗?肯定碰到过!你们讨厌吗?肯定早就把刷屏者屏蔽了。为了理解什么是Buffer Bloat并且基于此理解网络拥塞的本质,请暂时不要屏蔽这些人,如果你们觉得还想理解的更加深入些,请加上我。
            把你们的大脑看作是一种处理信息的资源,微信朋友圈里的内容则是资源的一种。请问,你每天花多长时间刷朋友圈呢?每次多久呢?好吧,我暂且估计是每次10分钟。这10分钟,你能看到多少内容,你又想看到什么内容呢?你希望的朋友圈是这样的:
    朋友1:
    我昨天晚上挨了一顿打!...
    朋友2:
    我女朋友跟我分手了...
    朋友3:
    我把工作辞掉了,无所谓了...
    朋友4:
    周五我请看电影,想一起的请点个赞!...
    朋友5:
    人,要学会忍受孤独,因为你的孤独与他人无关【转载的鸡汤文】
    朋友6:
    年末有好礼,你来我就送!【卖东西的广告】
    ....

    不可否认,这里面有你不喜欢的内容,比如那个鸡汤可能是你妈转的,虽然不喜欢也还是要点个赞什么的,卖东西的是你朋友或者上司不能得罪...然而,你之所以会花时间浪费你的大脑资源来刷朋友圈,还是希望得到一些你想看的东西的,你非常想看到朋友的八卦新闻,失恋离职之类的,隐约中其实在你内心也希望看到别人发一个生病的消息,然后回复一句无所谓的表现存在感的安慰,当然,你还希望可以从朋友圈信息中得到利益,比如有人请客什么的。
            对于发这些信息的人,他们渴望什么呢?既然发出去,就是希望有人看有人关注,不管什么目的,根本原因就是希望有人看!其目的不外乎以下几点:
    1.太寂寞(注意,不是孤独)了,需要安慰。当然,也不一定会发信息到朋友圈,这类人估计会同步信息到各个微博,博客,Facebook什么的(漂流吧,我的寂寞和我的泪!)。
    2.可能希望被某些人看到制造点影响力,比如让经理看到自己大半夜的电脑屏幕上有个Word文档,这样可能对自己加薪升职可以制造些筹码啥的...
    3...我不多扯了,这些话题与本文无关!

    你希望别人看到你发的信息,你希望别人评论你的信息或者转发你的信息,你希望得到关注,你希望获得一种存在感,在人世嘈杂中,你很寂寞,你害怕天黑...
    --------------------------------------------
    以上有买有卖,你来我往,写者有心,读者有意,看似非常和谐,就算是有人在朋友圈卖东西,相信也是不敢恶意刷屏的,偶尔发个链接啥的也要用哀求的口吻。但是如果你加上我,就不一样了,注意,请不要屏蔽我。你会看到以下的信息:
    我:
    温州老板是傻逼!
    我:
    我是傻逼!但这并不意味着其它所有人都是智者!
    我:
    赐予我水母吧,我是带鱼...
    我:
    温州皮鞋,下雨进水不会胖!
    我:
    不是经理的博士,不是好经理;
    不是博士的经理,不是好博士。
    我:
    .....
    我:
    ....
    我:
    .....
    我:
    ....
    我:
    .....
    我:
    ....
    朋友3:
    我要崩溃了,谁可以来帮帮我啊救救我!
    我:
    都是傻逼!
    我:
    .....
    我:
    ....

    你10分钟的大脑精力,全部被我占据!你不得不小心翼翼的往上翻屏,生怕漏掉了其它人发的重要信息(比如馈赠,求助之类的),10分钟时间转瞬即逝,只要我能保证在其它人发的最后一条有价值信息后发的所有信息够你玩10分钟的,我就制造了严重的Buffer Bloat!Buffer就是你的大脑!在这10分钟时间内,你不能刷刷刷地掠过我发的信息,你必须小心翼翼地去”过滤“每一条信息,因为在你看到这个信息是我发的之前,你不能确认它不是你其它的朋友发的!
            然后,你的大脑崩溃了!这就是拥塞崩溃!哦,对了,你可以从此屏蔽我,但现在还不是时候,因为我接下来还要再讲讲网络突发。
            如果说上面描述的我的行为是一种恶意制造Buffer Bloat导致了你的脑爆,那么下面的这种方式,则是一种正常的测试,我收回我的恶意。
            前几天,真的是前几天,我做了一个实验,那就是把我10月份以来发的所有朋友圈信息,全部删除,然后将它们全部在昨晚一次性发布。在删除之前,我的信息看起来是下面这个样子:
    我-2016/10/01:
    今天假期第一天,带着小小出去玩,记得去年的这个时候,我还在上海,时间过的好快啊!
    我-2016/10/03:
    假期也不能忘了学习,今天写了一篇文章,欢迎拍砖!【我在博客上的新发表的一篇文章】
    我-2016/10/07:
    假期最后一天,跟小小一起去爬山!小孩子体力比我好!【照片】
    我-2016/10/15:
    编程对抗赛报了名没参加,因为我不会编程,拿了一件衣服走人...
    我-2016/10/19:
    下班遇暴雨,漫漫回家路!
    我-2016/10/19:
    华尔眼中的最后一枪,来的有点早了
    我-2016/10/20:
    多年前写的代码,目前还在线上跑着...【一个代码截图】
    我-2016/10/22:
    【展示一组自己在家做的一顿饭】
    .....
    我将以上20条左右的信息删除,然后统一在昨晚同一时间发布,以下可能是你在随后看到的朋友圈:
    我:
    今天假期第一天,带着小小出去玩,记得去年的这个时候,我还在上海,时间过的好快啊!
    我:
    假期也不能忘了学习,今天写了一篇文章,欢迎拍砖!【我在博客上的新发表的一篇文章】
    我:
    假期最后一天,跟小小一起去爬山!小孩子体力比我好!【照片】
    我:
    编程对抗赛报了名没参加,因为我不会编程,拿了一件衣服走人...
    我:
    下班遇暴雨,漫漫回家路!
    我:
    华尔眼中的最后一枪,来的有点早了
    朋友2:
    .....(我也不知道你的朋友发了什么)
    我:
    多年前写的代码,目前还在线上跑着...【一个代码截图】
    我:
    【展示一组自己在家做的一顿饭】
    .....

    虽然,我的这一组信息或多或少都是有点意义的,然而,这绝非你所想看到的结果,因为你更多的看到所有朋友们发的消息,而不是我一个人发的。你的大脑天生有一个负载均衡机制,所以你非常讨厌任何形式的刷屏,不管是恶意的,还是像我上面那样一次性发很多的。
            但是你又能做什么呢?跟上次我恶意刷屏一样,你不得不一条条过滤这些信息,即便你不想看,你也得先确认它就是我发的,而这些动作,需要的是时间。在做这个“将10月1日至今的所有朋友圈信息删除后集中发送于此时”之前和之后,迄今为止我发送的信息总量完全没有变化,变化的只是之前是一天1到2条,此时是同一时间几十条,这对我而言,完全无所谓,但是却对你产生了非常不好的影响,记住,这种非恶意的集中发送导致你的脑爆,也是Buffer Bloat!
            好了,让我们回到现实!
            你使用的是微信,伟大的腾讯帝国的微信产品,所以你根本无需担忧被我刷屏!你可以选择从此以后屏蔽我,或者直接将我删除出好友的行列。如果你只是关心你发送的信息有没有被人回复而不关心其它人的信息,那你大可不必刷圈,微信自带了提醒机制,关于你的信息,只要有新的动态,就会单独提醒你,而无需你自己轮询查看。然而,你也只能在微信,以及类似的微博中享受这种服务(微博也有提醒机制,并且如果你特别烦某人,可以选择不再关注),这些产品,你可以看作是互联网时代的基石,让我们回到30多年前的纯粹TCP/IP时代再来看刷屏问题。
            请把一条一条的朋友圈信息看作是数据包,请把你的大脑看作是交换节点路由器,交换机或者目标端主机,非常糟糕的是,情况是一模一样的,然而不幸的是,路由器,交换机或者目标端主机们无法“屏蔽”或者“删除”那些造成Buffer Bloat的数据包!这些数据包有些数有意的,比如流氓UDP以及中国境内一切以TCP加速为目的的厂商所产生的流量,有些是无意的,比如几乎所有的TCP实现所发出的数据包(Linux的TCP没有实现Pacing机制,所以数据全部是在一个while循环中突发出去的,Pacing机制需要底层的Qdisc层来支持)。
            在继续下文之前,请不要扯防火墙,类比防火墙会“屏蔽”那些不想看到的信息。因为,防火墙要想屏蔽谁,首先也必须看到它并识别,而这一切,需要的是时间!你难道不知道网络中防火墙越多,延迟就越大吗?

    拥塞控制的本质意义

    你现在理解Buffer Bloat了吗?我想你已经理解了。然后我告诉你,Buffer Bloat导致了几乎全部的拥塞!在微信朋友圈的例子里,你知道怎么避免自己的脑爆(大脑的Buffer Bloat)吗?
            我们回到30年前,假设那时已经有了微信,已经有了你和我,并且你我是朋友,你无法屏蔽/删除我的前提下,避免Buffer Bloat的办法是什么??
            唯一办法就是,教育我,安慰我,祈求我,恐吓我不要再刷屏,不管是恶意刷屏还是无意的一次性发太多信息。除此之外,如果你有别的办法,我恭喜你,你已经找到了一种拥塞控制的方法,如果方便,请告诉我,如果经常看我的博客,应该知道我的邮箱,如果不知道,请搜索dog250所有与内核模块相关的,在代码中会找到我的邮箱,请告诉我你是怎么做的,昨天意外获得了几百块的红包,如果你能告诉我你的算法,我会发红包给你,真的!
            是的,让刷屏的人不刷屏,似乎是唯一的避免Buffer Bloat的方法。是的,拥塞控制的本质目的,就是避免Buffer Bloat,避免突发!请张大眼睛注意,拥塞控制的目标不是为了让你提高性能!绝对不是!相反,拥塞控制的目标是保障公平,避免不必要的消耗,这会达到一个典型的非零和均衡点,这是典型的中国式思维所不能理解且排斥的,然而事实就是这样子。
            带着一种错误的思路,大多数人在优化TCP的时候,眼睛死死盯着“窗口-时间”曲线的凹点,希望能填平它,却几乎根本上忽略了凸点,这是非常严重的错误。凸点意味着什么?凸点意味着上升不成功掉下去了,为什么掉下去,因为资源不足了,此时意味着发生了拥塞,典型的AIMD的锯齿尖尖的位置,就是这个凸点,这个点上发生的典型事件,就是丢包!
            和错误的思路相反,拥塞控制需要注意的是凸点,而不是凹点!
            以上说的是做TCP优化的一个惯用的伎俩,那就是见缝插针,只要能多发点数据,那就多发,这十分类似道路上那些傻逼司机到处变道,变来变去其实快不了多少一样的道理,这些变道司机的思维其实特别原始,它们只是只看眼前的阵势,操着自己还行的驾驶技术变换到空闲的车道,然后等空闲车道拥堵时再变回来,非常遗憾,这招不奏效!搞不好还要来一个令人悲伤的刮擦。
    ...

    真正的拥塞控制要做的是什么?

    真正的TCP拥塞控制要做的是,要判断在什么情况要少发数据,而不是多发!这不是一个自私的系统,这是一个博弈或者运筹的反馈系统,你的每一个行为都与全世界有关,这不是一个你能全面管控的自闭系统,这个反馈系统里面,你甚至都控制不了自己,你唯一能控制的,那就是自己在发现异常的时候尽量少发数据,评价算法好坏的指标就是你能否做到“多么恰到好处的少发数据”!也许你会说,TCP中基于时延的算法比如Vegas完败于基于丢包的CUBIC算法,而且Vegas就是按照我上面说的那种,发现异常就减速。你的疑问我很理解,但我要告诉你,CUBIC是错误的,CUBIC玩的是庞氏骗局,它相对于Vegas的高速传输行为事实上是一种透支行为。透支的是什么?透支的是“乘性减窗口”!CUBIC之所以还算优秀,那是因为几乎大家都在用它。世界上很多的服务器部署了Linux系统,而CUBIC又是Linux默认的拥塞控制算法,为了表现的好像在照顾那些弱者,CUBIC还引入了蹩脚的Friendly特性...
            那么谁是正确的呢?
            我认为BBR算法是正确的。因为它天生就按照无Buffer Queue的原则(一旦发现产生了Queue,就Drain掉它!)来设计,既然没有Queue,那自然就不会Buffer Bloat了,它是对的吗?这TMD才是真正的拥塞控制啊!
            也许你又要问了,既然正确的拥塞控制算法要避免Buffer Bloat,既然我说BBR避免排队的行为是一个“本质上正确”的行为,那么网络中的队列到底是干什么用的呢?好问题,下面一节我想详细展开这个问题。
    --------------------------------------------

    分组交换网络队列的本质与拥塞控制

    分组交换网和电路交换网完全不同,它采用统计复用原则,意味着在一个处理节点,数据包分组的到达的分布是符合泊松分布的,这就是说,队列是一定会存在的(泊松分布,马尔科夫到达决定了队列一定是存在的,必须在交换节点分配队列缓存)。
            这好像又回到了之前写的文章中描述的那些老路上了,要折腾一大堆数学公式,要搞一堆术语...但是你会发现,这篇文章写到这里还没有出现任何关乎专业术语的描述,以后也不会有,所以说,我打算通俗地解释一下为什么队列或者说排队现象是一定存在的,这里我不用泊松分布或者排队论的术语。这里我以城市快速路为例。
            道路交通系统是一个典型的统计复用的分组交换系统,其实早在TCP/IP分组交换网络之前,道路交通系统就已经存在了好几千年了,经典的例子就是古罗马的道路。但是年代久远了,扯那些就有点卖弄学问的意思了,所以说,以我们眼前的例子描述或许更加方便。
            本质上讲,队列是由于处理率小于到达率导致的!
            那么问题出现了,你让处理率大于等于到达率不就可以了吗?这是一个典型的学究式的反问。事实上,任何人都做不到让处理率大于等于到达率。原理很简单,你根本不知道到达率,到达率是事后算出来的,也就是说只有当到达的车辆或者数据包被处理了之后,才知道此时的到达率是多少,注意“此时”这个关键词,所以说,到达率是一个瞬时值,而不是一个持久的值。如果说把一段时间的所有的到达率采集下来,你会发现,这些到达率的值分布在一个可观测的范围内,数学家们仔细研究了这种分布,发现了规律,名曰泊松分布。
            只要你给定一个处理率,那么统计意义上,就一定会有到达率超过该处理率的概率,不管概率多么低,它是可能的,一旦发生这个事件,就需要一个队列来缓存未被即时处理的事件。
            现实中,大胆的设计者可能会说,把处理率设置成一段足够久的时间中采集到的到达率中的最大值不就可以了吗?至少99.9%的可能可以避免排队!这样可行吗?也许你已经知道了答案,不可行,因为这很浪费资源。但我的回答不是这样的。之所以不可行并不仅仅是浪费资源这么简单,而是基于统计复用的系统中,这样的设计是不可能实现的!我现在来简单证明一下这是为什么。

            我以全互通十字立交(靠右行驶)作为背景来证明这是为什么不可能设计出来的。要证明这种将处理率取最大到达率的系统是不可能设计出来的,我们就一步步地去设计它试试看,然后就知道为什么不可能了。请看下图:




    注意上图的红线,有这么一种可能性,那就是1,2,3号车道同时有车辆要汇入4号车道,必然有两辆车要排队等待,为了消除排队,按照大胆设计者的思路,正确的方案应该是下面的样子:




    是不是感到宽敞多了呢?然而,同时是不是也看出问题了呢?
            我们知道,条条大道通罗马的意思是所有的道路都是想通的,一个成熟的快速交通系统应该是没有断头路的,即没有路之尽头,这就是为什么几乎所有的快速交通系统都设计成环状加辐射状的原因。整个道路网是一个完整的系统,当然也就不止上图中那么理想化只有一个互通立交了,它的局部应该是下图的样子:




    请把这张图向上继续画下去,自己算一下过10座立交桥的时候,向北的车道是多少根!
    -------------------------------------------
    但是仅此只是说明了这么玩特别浪费资源,在市政府有钱的情况下,就算100根车道又如何呢。最大最好玩的问题要出现了。请试着把上面的图画成环试试....




    注意蓝色线,它标识了一种可能的车流汇集方向,按照避免排队的大胆设计,车道数会指数级增加无穷大!无穷大是一个抽象的数学概念,它并不真的存在(古人的googol是多少呢?)。所以说这种设计是不可实现的!
            这是一个咬尾蛇的困境,一条蛇咬住自己的尾巴,想把自己吃掉,请问结果如何?仔细思考这个问题,你会想通宇宙和人生的!
    -------------------------------------------
    到底哪里出来问题呢?为什么会进入无穷大的虚无困境呢?这背后的数学推理比较复杂,但是简单的说,那就是系统设计偏离了统计的均衡点。这个均衡点是一个不稳定的凸点,一旦稍微偏离,就会滑向万丈深渊!遵循统计均衡点的设计应该是下面的样子:




    非常平衡,非常稳定,然而带来的一个问题就是排队!事实上排队并不是问题,而是一种所有的统计复用系统本质上存在的一个属性,它的存在保证了系统的稳定和平衡!所以说,基于统计复用的系统,就叫做排队系统!
            除了道路交通系统之外,它还包括TCP/IP网络。
            每一个交换节点,都会有一个队列系统,不考虑碰擦等交通事故,也不考虑施工以及收费站等因素,正确的道路系统的排队全部都在匝道上,这里是道路交通网络的交换节点,类似TCP/IP网络中的路由器,交换机。在TCP/IP网络中,数据包不会在线缆中排队,只会在交换节点排队,这个与道路交通网络几乎是一致的。在道路交通网络中,发生在道路上的排队几乎全部是由冲突导致的,在TCP/IP网络,这点非常不同,TCP/IP分组交换网中,线路上的冲突会导致数据包的彻底丢失(参考CSMA/CD原理)而不是排队,因此就导致了两种模型的出现,即要么靠重传数据包解决线路上的冲突的问题,要么就彻底忽略冲突导致的数据包丢失,这就是TCP和UDP两种传输控制协议的设计理念的根源。
    -------------------------------------------
    说完了队列存在的根源之后,你应该已经默认了排队是不可避免的。那么队列是什么样子的呢?
            取决于交换节点的容忍度,队列分为深队列和浅队列。以刷朋友圈为例,在你发现有意义的信息或者干脆彻底放下手机干别的事之前,你能忍受我多少的刷屏,这决定了你的大脑队列的深度。
            在快速路交汇点的匝道,你会发现它们长短不一,匝道修多长并不是随意的,它是由队列长度决定的,而队列长度又和交通量有关。雨中的回家路,我无数次经过南北高架与汶水路的交汇处,那个匝道设计的不太合理,你能给出一个合理的设计吗?
    -------------------------------------------

    为什么高速网络要设计成环状

    你可能已经发现,几乎所有的高速网络都是环状的,比如城市快速路,IP骨干网等等。其实,这背后是有原因的。
            我是搞IT的,对网络方面比较熟悉,借此文我的目的是帮大家理解队列以及TCP拥塞控制背后的理念,在这一节,我依然不去深入描述路由器内部原理以及TCP拥塞控制算法的细节,那些细节是等你彻底弄懂了本质之后才需要去看的,诚然,即使你没有弄懂本质,甚至你根本上对本质一无所知,你也能看懂那些原理或者代码的细节(大多数高等教育出身的科班生不都是这样么?),但这种学习方式是不正确的。不多说,让我们开始吧!
            为什么要设计成环状呢?答案在于避免拥塞!
            已经在深圳一年了,这一年中我见证了这座城市的快速发展,我比较不关注房价菜价之类的事情,这些与我无关,我只关注道路。每到一个新的陌生的城市,我首先会一连几天看其地图,然后等熟悉了以后,没事就会看。看什么呢?看城市的道路。这里我举的一个例子就是深圳城市快速路系统的一个反例,我要告诉大家快速交通系统不按照环状设计是错误的。
            首先我们看一下深圳的快速路系统,我给一个不是详细且不是很全的简图,但足够说明问题了。图中红色道路为非快速路(会有红绿灯),但它们都是交通要道。现在我们来找下拥堵点,其实不用找了,在深圳的人没有不知道的:




    这些拥堵点有目共睹。现在我们来分析一下。
            你能在上图中找到几个环?很明确的可以看出,深圳城市中心,那几个红色圆圈的位置都不是环的一部分。因为我就在科技园上班,所以我们来分析一下附近与这个园区上下班流量息息相关的沙河西路/南坪快速的交汇处拥堵点。
            南坪快速与北环大道不成环,意味着经南坪快速西行进南山的车辆必须在南海大道或者沙河西路分流南行。以经验来看,人们都喜欢抄近路(非常遗憾的是,IP路由也是这个原则!)自东向西的车流不会绕道南海大道南行的(他们是宁可等也不愿绕,这是典型的透支第二类缓存的庞氏骗局!!),那么南坪快速沙河西路匝道会异常繁忙,事实上也是这样!
            下南坪快速进沙河西路南行出口处,有个红绿灯!就是这个红绿灯造成了该匝道的猛烈排队!
            因此沙河西路从南坪快速到滨海大道区间的快速化就是一个非常合理的需求。这样的话,沙河西路,滨海大道,香蜜湖路,北环大道,南坪快速,沙河西路就可以成为一个环,完全做到主道通行,匝道卸载的目的。
            一旦将沙河西路改造成快速路,那么沙河西路就变成第一类缓存了,没有时间墙,纯流量卸载的缓存。不然的话,这里就是一个带有时间墙的第二类缓存。
    -------------------------------------------
    接下来,在阐述统一的结论之前,我再给出上海市的城市快速道路网,毕竟那里是我生活了7年的地方,家底还在那边可能以后也会再回去。在下图中,我用红色圈圈标出了几个典型的拥堵点:




    因为我的家在嘉定,所以我对附近的道路更熟悉些,就以那边的为例子剖析了。
            我们仔细看图中实心红圈标出的拥堵点。我们把上海的这几个拥堵点和深圳南坪快速/沙河西路这个拥堵点做个比较,能看出什么规律吗?其实,它们都遵循下面的模式:




    即快速道路匝道下来的流量“侵入”到了不同向的其它非快速道路,我把这种匝道简称为“非同向侵入式匝道”,这种流量会在两个方向“打扰到”另外一条与之交叉的非快速路上的流量,而且,这种流量入侵几乎总是突发式的,上海外环/沪太路那里,跟南坪快速/沙河西路一样,平时非常好,只要到上下班高峰期,绝对堵成翔!
            和上面的那种非同向侵入式匝道相对,上海的很多高架路则完全不同,高架路上的匝道是下面的样子:




    即便是高架下来的流量,也是与地面道路同向的,并且仅此一个方向,不管是高架上还是地面道路,其通行方向一致,表明同一时间内其通行目标是一致的,地面道路可能仅仅是在最后一公里卸载了高架上的流量而已,我把这种匝道叫做“同向卸载式匝道”。在深圳,滨海大道,滨河大道也是这样子的设计。
            有了以上的概念,就很容易理解非同向侵入式匝道上为什么会堵成翔了。要做的只是把快速路围成环,这样就能将非同向侵入式匝道改为同向卸载匝道了,深圳南坪快速/沙河西路的方案如下:




    同样的道理,上海沪太路也要快速化:




    -------------------------------------------
    这跟成不成环有关系吗?看似没关系。仔细看上面两图中的1+1=2以及0.7+0.3=1这两个关系公式,你能看出点什么吗?
            请注意,环意味着什么?环就是一个圈,拥有每一个方向的圈,不管拐到哪个方向,都在这个圈上,环意味着没有尽头。这似乎不太好理解,那么我们来看下什么不是环。线不是环,它是有尽头的,在一个拥有尽头的统计复用的网络中,队列将是无限大的,因为这里有一堵墙,时间墙!作为最后一个例子,我们来看看我家门口附近的一个拥堵点,那就是上海沪嘉高速/叶城璐交汇处。这里是沪嘉高速的尽头(其实也可以理解成一个位于进入G1501主道收费站右边的一个匝道出口)!只要沪嘉高速上有哪怕一点进入嘉定城区的流量,这个出口的位置一定持续性堵成翔!为什么?很简单,出口出去后都是普通道路,而沪嘉高速则是限速80km/h(改造前是120km/h)的城市快速路,到达率远远大于处理率!那为什么不是一直堵到中环汶水路呢?这里到达率的泊松分布可以解释,我就不解释了。
            沪嘉高速终点这个地方,是一个非常典型的路之尽头,其拥堵也非常好解释。对于深圳南坪快速/沙河西路这个点,你能意识到它事实上也是路之尽头吗?
            虽然在物理上,这里只是一个通往沙河西路的匝道,但事实上,再往前走就是南头了,中间再没有匝道,绝大多数的进入西丽或者南山科技园的车辆都会在沙河西路出口下去,因此这里是一个事实上的路之尽头,所以说,这就解释了为什么这里会这么堵。怎么办?围成环。将南北向的沙河西路也纳入东西向的南坪快速的一部分,消除掉这个尽头即可。消除了路之尽头,也就消除了在路之尽头典型的线头拥塞问题!
    -------------------------------------------
    现在可以下结论了。想要快速,就必须成环!因为只有围成环才能将侵入式流量转化为卸载流量。这里,对于道路交通网而言,宁可等也不愿绕可能是由人的心理决定的,这是典型的透支第二类缓存的庞氏骗局!!遗憾的是,不管是城市中的车流,还是OSPF等路由协议,或者CUBIC拥塞控制算法,都在玩这种透支行为。
            如果你有时间,研究一下IP骨干网的拓扑,然后Trace一下几个关键节点,观测到达它们的RTT变化情况,你会发现,这就是一张IP数据报文的道路交通网!与现实中的城市道路交通网络几乎是一致的。而且在司机越来越依赖导航的节奏下,两个网络会越来越一致。向我这种偏偏不按“最短路径”走的人越来越少了,因此能主观上避开拥堵的也会越来越少。
            说点题外话结束本节。导航是机器控制人的一个典型例子。之前都是司机自己看纸质地图,然后自行决定怎么走,现在还有几个人能看懂地图?!大家基本都是听着“前行300米后向右边进入辅道”这种指示开车的。姑且不说拥堵,更加严重的事情都可能发生,把人车带进沟里的还少吗??
            IP路由表是OSPF算出来的,现在你开车出行的路线也是OSPF算出来的,大家同一时间堵在同一条路上,统一拿出手机开始刷刷刷,于是乎大量突发的数据包统一发送到最近的同一个基站,然后统一到达同一个路由器被分发交换,于是这些数据包也堵在同一个路由器里...车在路上等啊等,道路还是不通,人在车里刷啊刷,页面却怎么也不肯出来!两个网络同步拥堵。

    该结束了

    本文写到这里该结束了。其实还有很多话题没有展开,比如关于布雷斯悖论的话题,其实也是很有意义的。关于此话题,我建议大家研究一下韩国首尔拆路治堵的例子,然后试着分析一下上海沪翔高速与沪嘉高速为什么没有互通。
            拥塞控制是一个合作式的控制机制,而不是一个对抗式的控制机制,因为本身统计复用的网络就是一个合作式的系统而非对抗式的系统,合作才能共赢。所以说,在这么一个拥有蝴蝶效应(你的行为的结果与全世界有关)的合作系统中,所有的小聪明汇总的结果就是一场大拥堵。正如车辆堵在路上无法飞走一样,数据包在路由器队列里也无法排出,只能等。发现拥塞总是滞后的,只有当拥塞实际发生的时候才能发现拥塞,但此时已经晚了!于是人们希望可以预测拥塞,那么预测也就只能基于历史来预测将来,本来所有开车的人都知道哪哪路段在什么时间会堵车并视情况而绕开,但自私的小聪明让他们执意选择去添堵,这是一场自私者之间的博弈!
            OSPF协议按照度量计算最短路径,然而度量本身怎么去度量?这就是问题。这个问题导致了网络拥塞。人们普遍认为路由的收敛速度是一个性能指标,越快越好,但我的观点与此不同,我觉得越收敛的路由越容易发生拥塞,因为大家算出来的最短路径是一致的。
            BGP路由协议天生就有抗堵的功能,然而大家都说它是基于Policy的,不是自治的,SDN也能全局控堵,然而大家指责它是集中独裁的,而非“失控”的,在“失控”的互联网世界,拒绝独裁。
            争议总是不断,所以说拥塞控制更像是社会科学的范畴而非自然科学。就在上周五,我跟同事开了个玩笑,我们的周五下午总是非常轻松,如果大家都没啥事,晚上还能聚餐,上周五的时候,大家商量去吃饭,4点多出发,由于几个同事工作上有点事要处理,所以就分两拨人走,处理工作的晚点出发,正好赶上下班高峰期堵车,吃饭的地方又没有地铁公交,只能开车或者打车,没人开车只能打车,我给了个建议,打100辆车,把自己复制100份,总有一辆能到!
            虽然在道路交通网上,你不能把自己复制100份,你甚至不能把任何一件东西复制100份,但是TCP/IP网络是可以的。于是各种令人作呕的加速方案就出现了,一个包发两遍是一种最简单的方案,假设丢包率是5%,那么两个都丢的概率就是5%*5%了,是这个数字化的概率吸引了设计者,另外还有抢着发包的,观察若干连接的吞吐量/时间曲线,发现凹点就查代码,打日志,重现凹点,看看到底发生了什么,最终的目的是填平这个凹点,这个思路比一个包发两遍聪明了很多,还有更加激进的,直接忽略拥塞窗口,眼里容不得窗口下降,甚至连对端通告窗口都忽略,没事了就要发几个数据包...唉!太悲哀了。幸亏现实中的人和物品不能复制,万一要是能了,在我们这个伟大的地方,道路真的就全部都成停车场了。
            拥塞全部都是Buffer Bloat的后果,有一种DDoS导致的Buffer Bloat你们听过吗?这“归功”于我们的专利制度!只要是比较有名气的大公司放出几个专利,那么就会有别的公司投入巨量的人力物力来“偷偷摸摸”实现这个专利,因为在中国人的眼里,越是你拼命保护的东西,就越容易引贼惦记。我们反其道而行,累死那帮贼!以大公司名气,放出几个根本没有价值和意义的专利,吸引那些别的公司去偷摸实现,这样会消耗掉他们大量的资源,导致他们根本干不了正事,是不是跟刷屏的效果一样呢?
            我以刷屏开始本文,以类似刷屏的DDoS来结束本文。
            看来事情还没有结束,虽然事情还没有结束,但是本文真的该结束了!
    展开全文
  • MongoDB的分组统计 group

    千次阅读 2018-12-28 14:19:35
    mongodb中的分组聚合用$group,而且处理的最大数据量为100M如果超出需要写入到磁盘,使用格式如下: 1 { $group: { _id: &lt;expression&gt;, &lt;field1&gt;: { &lt;...
  • Hive分组统计前top N条记录

    千次阅读 2017-01-22 18:45:04
    参考这篇博客而写:...本 Hive 语句的目的统计中国每个省份下所有城市记录出现总次数为前5的结果。 hive -e " select bb.* from ( select country_name, province_name, city_name
  • elasticsearch分组统计性能优化

    千次阅读 2019-01-16 10:08:52
    最近用es做数据统计时,增加了一个统计维度,发现查询性能下降了十几倍,查询es文档发现 Terms Aggregation 的计算方式主要有以下两种: map,在内存中构建映射表,利用映射表完成聚合计算,可以看得出,这种方式...
  • 实验6 数据库的分组查询和统计查询 6.1实验目的及要求 熟练掌握数据查询中的分组统计、计算和集合的操作方法 6.2实验内容 使用聚集函数查询、分组计算查询、集合查询 6.3实验步骤 6.3.1使用聚集函数 1....
  • 文章目录数据聚合与分组操作一.GroupBy机制1.1遍历各分组1.2选取一列或所有列的子集1.3 通过字典或Series进行分组1.4 通过函数进行分组1.5根据索引层级分组二. 数据聚合2.1面向列的多函数应用2.2返回不含行索引的...
  • Lucene聚类分组统计功能(grouping)

    万次阅读 2011-09-18 16:56:38
    在搜索的项目中,我们经常有搜索结果进行分组字段进行压缩的需求。之前的文章提到这个功能已经添加到solr中并成为用户一个非常需要的特性。最近结果分组被作为一个扩展包加入到lucene3.1中,而在4.0中将直接...
  • 使用java操作mongodb实现按天分组统计

    千次阅读 2018-01-30 10:51:59
    由于需要使用mongodb来统计数据,但是网上的资料实在是少的可怜,也是我收集资料能力不行,反正就是找不到我要的,又没有人可以问,刚接触这个数据库,强大是真的,但是一个小需求就搞掉了我几天时间,生气.刚入行的小白,...
  • 不过相对于普通的增删改查,group操作就略微麻烦一些,这里group在shell中的操作、使用java原生代码操作以及集成spring进行操作进行一个简单的归纳总结,分组的途径和方法应该都有多种,这里每一样只举一例。...
  • mongodb的mapreduce的分组统计

    千次阅读 2013-08-23 11:14:10
    finalize:和map,reduce一样是一个函数,它可以在reduce得出一个结果后再key和value进行一次计算并返回一个最终结果 scope:设置参数值,在这里设置的值在map,reduce,finalize函数中可见 verbose:在...
  • 分组使用group,如果指定字段就按字段分组,但是数据会有重复,于是参考文档想到不指定字段,按添加字段来分组,就可以达到统计分类并去重的目的。 搭配聚合操作,使用$取数据库中的指定字段数据,即可解决。 需求:...
  • oracle 分组统计相邻的行

    千次阅读 2011-06-01 17:27:00
    //我们想让相邻的行取得相同的p3值,将id-rn作为分组的一个选项,那么就可以达到目的了 //下面是部分数据: id p1 p2 id-rn 1 A NULL 0 2 A NULL 0 6 A NULL 3 //这样,我们按照id,p1,p2,id-rn分组,就得到结果了  ...
  • 用Linq将成绩按不同分数段进行分组

    千次阅读 2015-01-31 21:45:03
     一个学院所有教师的总成绩进行统计分析,显示不同分数段(0~59,60~69,70~79,80~89,90~100)各占多少人,从而直观地展现整个学院教师受学生欢迎程度。 问题:  我通过底层方法,返回一个集合,这个集合中每个...
  • 分组交叉报表的统计图制作起来非常简单,只需要选取统计图的图形效果便能得到预期的统计图,这是由于统计图的分类系列能够按照一定的取数规则自动获取分类系列值,不需要用户再单独规定和修改其取值。  既然统计图...
  • 正态分布检验一次只能检验一个分组,如果有多组数据需要检验,则需要运行多次 解决思路 使用循环命令可以实现按一定规则计算。 如果以后也经常需要使用,写成脚本调用更方便些,需要使用的时候直接调用即可。 ...
  • 自定义分区的目的是在根据年份分好了组之后,将不同的年份创建不同的reduce task任务,因此需要年份处理。 import org . apache . hadoop . io . Text ; import org . apache . hadoop . mapreduce . ...
  • SPSS数据分组

    万次阅读 2018-08-24 14:59:31
    数据分组,根据分析目的将数值型数据进行等距或非等距分组,这个过程也称为数据离散化,一般用于查看分布,入消费分布、收入分布、年龄分布等 在SPSS中主要使用可视分箱来数据分组操作,首先打开数据,点击转换...
  • 漫谈分组交换网

    千次阅读 2021-03-27 07:22:15
    互联网和电话网的差异就是 分组交换 和 电路交换 吗?教科书上就是这么讲的,但这就够了吗? 远远不够,所以我补充下缺失的部分。 19世纪电话的发明是人类通信史上的创举。 电话的意义不在电话本身,而在于越来越多...
  • 可以看出,这步的目的是把相同的userid只剩下一个。 然后第二步,再第一步的结果之上再执行统计: >db.t2.aggregate([   { $group: {"_id": { "country" : "$country", "province": "$province" , "uid" : ...
  • 分组函数

    千次阅读 2018-10-15 22:49:21
    分组函数 常用的一些函数 AVG(sal), MAX(sal), MIN(sal) MIN(hiredate) , MAX(hiredate) 中间的工资值 MEDIAN(sal) 标准差与方差 STDDEV(sal),VARIANCE(sal) 注意事项一: 如果没有GROUP BY子句,则在SELECT...
  • pandas的groupby功能,可以计算 分组统计和生成透视表,可数据集进行灵活的切片、切块、摘要等操作GroupBy技术“split-apply-comebine”(拆分-应用-合并)
  • 转载自: ...计算分组摘要统计,如计数、平均值、标准差,或用户自定义函数。DataFrame的列应用各种各样的函数。应用组内转换或其他运算,如规格化、线性回归、排名或选取子集等。计算透视表或
  • 分组交换(存储-转发)

    千次阅读 2020-10-12 09:39:20
    分组交换: 通信中,通信双方以分组为单位,使用存储-转发机制实现...能够进行分组交换的通信网被称为分组交换网。 分组交换的本质就是存储转发,它将所接受的分组暂时存储下来,在目的方向路由上排队,当它可以发送信
  • 面对此种情况,我们可以利用FME软件进行数据的统一分类,像名称相同的或名称相似度度比较高(大于0.5)及以上的,可以做一个统一编号,方便后续数据进行处理,提高工作效率。 2FME处理流程 ...
  • 分组键可以有多种形式,且类型不必相同 a.列表或数组,且长度与待分组的轴一样 b.表示DataFrame某个列的值 c.字典或Series,给出待分组轴上的值与分组名之间的对应关系 d.函数,用于处理轴索引或索引中的各个标签 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 49,451
精华内容 19,780
关键字:

对统计资料进行分组的目的