精华内容
下载资源
问答
  • 志在巅峰的攀登者,不会陶醉在沿途的某个脚印之中,在码农的世界里,优美的应用体验,来源于程序员细节的处理以及自我要求的境界,年轻人也是忙忙碌碌的码农中一员,每天、每周,都会留下一些脚印,就是这些创作的...

    志在巅峰的攀登者,不会陶醉在沿途的某个脚印之中,在码农的世界里,优美的应用体验,来源于程序员对细节的处理以及自我要求的境界,年轻人也是忙忙碌碌的码农中一员,每天、每周,都会留下一些脚印,就是这些创作的内容,有一种执着,就是不知为什么,如果你迷茫,不妨来瞅瞅码农的轨迹。


    1 前言

    如下我这里有两张表,表t1为某活动的报名信息表,部分建表 DDL 如下:

    CREATE TABLE `t1` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `activity_id` bigint(20) DEFAULT '0' COMMENT '关联的活动信息',
      `user_id` bigint(20) DEFAULT '0' COMMENT '报名人的ID',
      `create_time` datetime DEFAULT NULL COMMENT '报名时间',
      `remark` varchar(255) DEFAULT NULL COMMENT '备注',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=18  COMMENT='活动报名表';
    

    表t2为 投票信息表,也就是说 t2表中保存的是给t1表中的报名用户投票记录信息,部分建表 DDL 如下:

    
    CREATE TABLE `t2` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `activity_user_id` bigint(20) DEFAULT '0' COMMENT '关联的活动报名信息 t1表中的id',
      `vote_user_id` bigint(20) DEFAULT '0' COMMENT '投票者的信息',
      `create_time` datetime DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `activity_user_id`(`activity_user_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=226 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='用户投票记录表';
    

    现在 我 t1 表中有 10 条数据
    在这里插入图片描述
    t2表中 84 条数据,如图所示

    在这里插入图片描述

    现在有一需求就是查询 户的投票记录以及报名信息,那么我们需要从 t1表中获取报名信息,然后再从t2表中获取每个用户的投票记录。

    那么无非就是有两种查询思维,一种是先取t1,再循环取t2,另一种是使用 join ,那到底使用哪种,你是怎么决定的呢???

    1 我们先来看看 循环查询

    在不使用join的情况下,我们需要先从t1表中查出这用户的报名信息,然后循环从t2表中查询投票信息,这个过程如下


    • 执行select * from t1 ,每一行数据记为 C,这一步会对t1表进行全表扫描,我们t1表中是10条数据,全表扫描10行

    在这里插入图片描述

    type = ALL,全表扫描,MYSQL扫描全表来找到匹配的行

    • 然后循环遍历这 10 行数据,从每一行 数据 C 中取出字段 id 的值; 执行select * from t2 where activity_user_id=id;(activity_user_id走的是索引树搜索) 把返回的结果和 C 构成结果集的一行。

    在表t2中,满足 t1表中id为12的有49条数据
    在这里插入图片描述
    这个过程中 扫描 49行数据

    在这里插入图片描述

    type = ref ,使用非唯一性索引或者唯一索引的前缀扫描,返回匹配某个单独值的记录行。

    满足 id 为13的有 35条数

    在这里插入图片描述
    这个过程中扫描35行数据

    在这里插入图片描述

    然后 t1 表中其他 8条数据在表 t2中没有记录,所以查询过程中各扫描一行。

    在这个过程中,这样查询下来,需要在业务代码中自己组装循环查询,t1表扫描 10行,t2表扫描 35 + 49 + 8 = 92,查询完成总共扫描 102行数据。


    2 使用 join 时

    当使用 join 时,可以这样写 :(使用 STRAIGHT_JOIN 保证固定联表顺序)

    SELECT
    	* 
    FROM
    	t1  STRAIGHT_JOIN  t2 
    	ON (t1.id = t2.activity_user_id )
    

    满足条件的有 84 条数据
    在这里插入图片描述

    这个语句的执行流程是这样的:

    • 第一步 从表 t1 中读入一行数据 C;
    • 第二步从数据行 C 中,取出 id 字段到表 t2 的 activity_user_id 索引树中搜索;
    • 第三步 取出表 t2 中满足条件的行,跟 C 组成一行,作为结果集的一部分;
    • 第四步 重复执行步骤 1 到 3,直到表 t1 的末尾循环结束。

    在这里插入图片描述

    这个过程是先遍历表 t1,然后根据从表 t1 中取出的每行数据中的 id 值,去表 t2 中查找满 足条件的记录,这个过程称为 “Index Nested-Loop Join”,简称 NLJ。

    在这个过种中,t1表是驱动表,是走全表扫描,t2是被驱动表,是走树搜索,所以在 join过程中,应该让小表作驱动表。

    此时 我们将 t2表中的 activity_user_id 索引删除

    在这里插入图片描述
    我们再查询一下

    在这里插入图片描述
    我们可以清楚的看到当不走索引搜索时,t1与t2都走了全表扫描,

    执行过程如下

    • 第一步扫描表 t1,顺序读取数据行放入 join_buffer 中,假设放完第 3 行 join_buffer 满了,继续 第二步操作;
    • 第二步 扫描表 t2,把 t2 中的每一行取出来,跟 join_buffer 中的数据做对比,满足 join 条件的,作为结果集的一部分返回;
    • 第三步 清空 join_buffer;
    • 第四步 继续扫描表 t1,顺序读取最后的 7 行数据放入 join_buffer 中,继续执行第 二 步。

    这时候由于表 t1 被分成了两次放入 join_buffer 中,导致表 t2 会被扫描两次,这个过程就是 “Block Nested-Loop Join”。

    显然 这两种情况 “Index Nested-Loop Join” 与 “Block Nested-Loop Join” 分析得出,如果可以使用到被驱动表中的索引,就可以使用 join 来查询。

    如果无法使用到被驱动表的索引查询,这样可能要扫描被驱动表很多次,会占用大量的系统资源,所以这种情况下 join 尽量不要用。


    完毕

    不局限于思维,不局限语言限制,才是编程的最高境界。

    以小编的性格,肯定是要录制一套视频的,随后会上传

    有兴趣 你可以关注一下 西瓜视频 — 早起的年轻人

    在这里插入图片描述

    展开全文
  • MSDN对子查询的定义是这样的: 可以将一个查询的结果用作另一个查询的输入。可以将子查询的结果用作使用 IN() 函数、EXISTS 运算符或 FROM 子句的语句。...明确的连接选择的顺序和找到最可能的计划给出了...
       MSDN对子查询的定义是这样的:

         可以将一个查询的结果用作另一个查询的输入。可以将子查询的结果用作使用 IN( ) 函数、EXISTS 运算符或 FROM 子句的语句。

         一条好的值得称赞的规则是尽量用连接代替所有的子查询。优化器有时可以自动将子查询“扁平化”,并且用常规或外连接代替。但那样也不总是有效。明确的连接对选择表的顺序和找到最可能的计划给出了更多的选项。当你优化一个特殊查询时,了解一下是否去掉自查询可产生很大的差异。这段话出自http://www.innovatedigital.com/htm_speek/SQLServerOpt.shtml它显然告诉我们在查询的时候最好不要用子查询,当时我并不太在意,至到我有一次遇到了这样的情况。  
          
         现在的网站主要的压力都来自于数据库,频繁的数据库访问经常会使服务器死机。我的原则就是尽量减少数据库的连接,能一次性取出的决不多连接数据库一次,但是有时候并不完全是这样。郁闷,无解。    
     

         基于有的朋友看不明白我写的SQL语句,可能是因为我写的有些字段和本案例没有太大关系的原因,现在特将它们做一个替换.
         

         我的项目里面有两张表:

        1:电影表,里面都是些电影的详细信息.

        字段说明:RESOURCE_VOLUMECOUNT
                    它是指一个电影共有多少集.这个字段是int类型的

         其它的和本案例关系不大的字段就省略了.

         2:电影文件表:TB_RESOURCE_PRIMARVIDEO

           它是指电影表里面的具体电影实际存在的集数,例如:功夫有1集,是通过电影ID(resource_id)与电影表关联的.电影表和它是一对多的关系.其它的和本案例关系不大就省略了.

         需求:

              取电影信息记录集,并算出各个电影的缺集情况.例如完整的一总功夫电影应该要有两集,但是电影文件表里面只有一集,那么此时电影缺集为.

      

         下面一条SQL语句里面有一个子查询,info.RESOURCE_VOLUMECOUNT,它是指一个电影共有多少集.这个字段是int类型的.子查询的目的就是计算出一个电影在资源表中总共有多少集(实际存在的), 两者做减法操作就可以计算出这个电影共缺多少集(lastCount)我们知道在这条语句执行的时候,外层记录查询一次在计算 lastCount字段的时候又要查询表:电影表一次.如果最外层有10条记录,那么执行这次查询一共要扫描电影表11次,连接数据库1次.
         

       


    string SqlCode = @"select distinct info.resource_officialname ,
              info.resource_id,
              字段1,         
               (
                 
    info.RESOURCE_VOLUMECOUNT -
                   (select count(vid3.resource_id ) from 电影表 info3
                     inner join TB_RESOURCE_PRIMARVIDEO vid3 on
                      info3.resource_id =vid3.resource_id and
                      info.resource_id =vid3.resource_id 
                      
                   )
               ) as lastCount,
              字段2
              from 电影表 info
               where 1=1 
    ";
         
        现在换一种方法来做:

         下面的语句和上面的语句只有一个区别就是没有查询lastCount字段,但是查询出了info.RESOURCE_VOLUMECOUNT字段(完整电影应该有的集数),就是说去掉了那个子查询.在绑定数据的时候,通过每次记录的resource_id(电影ID)重新进数据库执行一次以前的子查询,

        具体实现是这样的:
        在外层记录做循环的时候,通过resource_id来取电影实际存在多少集.在程序中来实现info.RESOURCE_VOLUMECOUNT与"电影实际存在的集数"做减法.这样做也是查询表:电影表总共11次,连接数据库11次.

    private string getCount(string resource_id)
    {
       
    //返回结果
       string s="";
       
    string sql=@"select count(vid3.resource_id ) from 电影表 info3
                     inner join TB_RESOURCE_PRIMARVIDEO vid3 on
                      info3.resource_id =vid3.resource_id and
                      info3.resource_id =
    "+  resource_id;
       
    //执行代码省略
       return s;         
             

    }

         下面是去掉了子查询的SQL查询语句。它是最外层的循环,每循环一条记录后用取得的电影ID再调用上面的方法去计算此电影实际有多少集,这样在功能上就与第一种方法(包含子查询)得到的结果是一样的了。但是在效率上有太大的差距。

    string SqlCode = @"select distinct info.resource_officialname ,
              info.resource_id,
              字段1,         
                
    info.RESOURCE_VOLUMECOUNT,--完整电影应该有多少集
             字段2
              from 电影表 info
               where 1=1 
    ";

         理论上说应该是查询表11次打开数据库连接1次的在性能上应该会好很多啊,但是实际不则相反,反而是查询表11次打开数据库11次之多的后一种方法在执行时间上会少很多.不知道这样的子查询在实际数据库操作中到底会有多大的实际用处呢,是否真是鸡肋呢?我在实验的时候当数据特别少时差别不大,一旦多了,哪怕只有1000条,性能上都有特别大的差距,有时会出现死机的状况。我用的是interBase下的firebird数据库,这里不能显示出执行的具体时间,抱歉了。虽然是小型的,但是也能反应出问题来,希望高手们看到了能帮我分析一下其中的原因,我们在查询数据的时候是否还能用这样的子查询呢?

         本人的文章发布之后有很多朋友都给出了自己的想法,很多都不错,主要的一种说法就是利用join来替代子查询,可是如果说在取出的字段特别多的时候,进行分组时 group by  中会出现多个字段,这在性能上也未必会好.而且这只是一种解决方案,能不能以我文章中的性能问题分析一下具体原因呢?为什么第二种方案效率会更好呢?

    转载于:https://www.cnblogs.com/ASPNET2008/archive/2008/05/13/1194815.html

    展开全文
  • 我这上面一段sql,查询的是一个一多的关系,取多方最新的一条数据,现在我HISTORY表里有2万条数据,最后查询出来的少了几千条,也就是说 我多方那个里面没有记录,它取不了,然后就不显示吗?不应该有一条空数据...
  • 数据库设计时一一关系存在的必要性 2017年07月24日 10:01:07 阅读数:694 在设计过程中,我无意中觉得一一关系觉得好没道理,直接放到一张中不就可以了吗?真是说,网上信息什么都有,也...

    数据库表设计时一对一关系存在的必要性

    在表设计过程中,我无意中觉得一对一关系觉得好没道理,直接放到一张表中不就可以了吗?真是说,网上信息什么都有,也可以说与我一样困惑的有好多人。感谢大神在网上的活跃,我知道了一对一关系存在的必要性。

    1.首先就是这种关系出现的场景是什么样子,最好可以举个实际中的需求。

    这样的场景有很多,比如:就拿最普通的用户信息来说,数据库中有一个表为user,一个表为user_auth.user表主要存放的字段为用户基本的信息(用户ID、真实姓名、昵称、真实头像、性别、职位、教育程度、专业、创建该用户的时间等),而在user_auth为验证表(用户ID、用户密码、邮箱、手机号等)。当涉及到一个具体实体的信息量较多,或者可以分类的时候,就可以使用了1-1,当然只要你能把一个实体的关系拆分成几个有归类的部分也可以适用。

    2.为什么要使用两个表来维护一对一关系,为什么不直接将两个表中的字段全都放在一张表里来展示?

    如果都放在一张表里,一:不便于管理(包括查询执行速度),二:也就达不到关系型数据库的特性。三:可更好对业务进行事务隔离操作

    3.提出这种关系的目的是什么,就是为提高我们数据库查询条件吗?

    目的:为第二问答案。这与数据库查询条件没有必然的说法。你说查询速度或者为了方便区分查询管理还说得过去。

    还有

    1. 公司和公司地址,总经理和公司,部门经理和部门 都是一对一

    2. 对于小字段小数据量的数据库来说,放到一起无所谓了,但是对于大字段的数据库,要添加删除修改某一个字段,由于数据库大,字段多,数据库找到这个字段耗时久,造成锁表等问题。同时分离存储大数据的表时,查询也会节省时间,因为某些框架会映射表里面所有的字段,存在一起查询时会把不需要的字段也映射进来造成耗时过久。还有,大数据量的表分离存储对于索引创建,读写分离,分割等操作都有优势。

    3. 同2

    我觉得这两种答案比较好。COPY在这里,记得时常看看,记在心里。

     

     

    数据库一对一、一对多、多对多设计

       做一个项目,必然是少不了数据库设计的!在学习阶段,基本都是单表。然而在实际开发过程中,一对多,多对多的表处处都是!简单整理一下,一对多,多对多表如何设计整理一下思路:

           数据库实体间有三种对应关系:一对一,一对多,多对多。

           一对一关系示例:

      • 一个学生对应一个学生档案材料,或者每个人都有唯一的身份证编号。

           一对多关系示例:

      • 一个学生只属于一个班,但是一个班级有多名学生。

           多对多关系示例:

      • 一个学生可以选择多门课,一门课也有多名学生。

    1.一对多关系处理:

           通过学生和班级问题了解一对多:

           设计数据库表:只需在 学生表 中多添加一个班级号的ID;

    注:在数据库中表中初学时,还是通过添加主外键约束,避免删除数据时造成数据混乱!

     

    2.多对多关系处理:

        通过学生选课了解多对多问题的处理:

     

           在多对多中在一个表中添加一个字段就行不通了,所以处理多对多表问题时,就要考虑建立关系表了

    例:

     学生表:     课程表:   关系表:

     

    注:所以对于多对多表,通过关系表就建立起了两张表的联系!多对多表时建立主外键后,要先删除约束表内容再删除主表内容

     

    面试逻辑题3.31

     
    1. 你让工人为你工作7天,给工人的回报是一根金条。金条平分成相连的7段,你必须在每天结束时给他们一段金条,如果只许你两次把金条弄断,你如何给你的工人付费? 
      答案:第一天给1段,第二天让工人把1段归还后再给他给2段,第三天给1段,第四天让工人归还1、2段,给4段。第五天依次类推……

    2. 请把一盒蛋糕切成8份,分给8个人,但蛋糕盒里还必须留有一份。 
      答案:面对这样的怪题,有些应聘者绞尽脑汁也无法分成;而有些应聘者却感到此题实际很简单,把切成的8份蛋糕先拿出7份分给7人,剩下的1份连蛋糕盒一起分给第8个人。

    3. 小明一家过一座桥,过桥时是黑夜,所以必须有灯。现在小明过桥要1秒,小明的弟弟要3秒,小明的爸爸要6秒,小明的妈妈要8秒,小明的爷爷要12秒。每次此桥最多可过两人,而过桥的速度依过桥最慢者而定,而且灯在点燃后30秒就会熄灭。问:小明一家如何过桥? 
      答案:这类智力题目,其实是考察应聘者在限制条件下解决问题的能力。具体到这道题目来说,很多人往往认为应该由小明持灯来来去去,这样最节省时间,但最后却怎么也凑不出解决方案。但是换个思路,我们根据具体情况来决定谁持灯来去,只要稍稍做些变动即可:第一步,小明与弟弟过桥,小明回来,耗时4秒;第二步,小明与爸爸过河,弟弟回来,耗时9秒;第三步,妈妈与爷爷过河,小明回来,耗时13秒;最后,小明与弟弟过河(不用回来了),耗时3秒,总共耗时29秒。

    4. 一群人开舞会,每人头上都戴着一顶帽子。帽子只有黑白两种,黑的至少有一顶。每个人都能看到其他人帽子的颜色,却看不到自己的。主持人先让大家看看别人头上戴的是什么帽子,然后关灯,如果有人认为自己戴的是黑帽子,就打自己一个耳光。第一次关灯,没有声音。于是再开灯,大家再看一遍,关灯时仍然鸦雀无声。一直到第三次关灯,才有劈劈啪啪打耳光的声音响起。问有多少人戴着黑帽子? 
      答案:假如只有一个人戴黑帽子,那他看到所有人都戴白帽,在第一次关灯时就应自打耳光,所以应该不止一个人戴黑帽子;如果有两顶黑帽子,第一次两人都只看到对方头上的黑帽子,不敢确定自己的颜色,但到第二次关灯,这两人应该明白,如果自己戴着白帽,那对方早在上一次就应打耳光了,因此自己戴的也是黑帽子,于是也会有耳光声响起;可事实是第三次才响起了耳光声,说明全场不止两顶黑帽,依此类推,应该是关了几次灯,有几顶黑帽。

    5. 一楼到十楼的每层电梯门口都放着一颗钻石,钻石大小不一。你乘坐电梯从一楼到十楼,每层楼电梯门都会打开一次,只能拿一次钻石,问怎样才能拿到最大的一颗? 
      答案:这是一道没有标准答案的试题,实际上它考的是你的开放性思维和逻辑推理能力. 
      第一步:对1到3层的大小进行比较,记住最大的一颗。 
      第二步:4到6层作为参考,将4-6层的最大的跟1-3层的最大的作比较,确认最大的一个的平均水平。 
      第三步:在最后4层中选择一个属于最大一批的,如果第7层的就是最大的平均水平的,那就闭上眼睛不再观察之后的。这就是最大的一颗。

    6. 烧一根不均匀的绳要用一个小时,如何用它来判断半个小时? 
      答案:两边一起烧。

    7. 为什么下水道的盖子是圆的? 
      答案之一:从麻省理工大学一位计算机系教授那里听来的答案,首先在同等用材的情况下他的面积最大。第二因为如果是方的、长方的或椭圆的,那无聊之徒拎起来它就可以直接扔进地下道啦!但圆形的盖子嘛,就可以避免这种情况了

    8. 有7克、2克砝码各一个,天平一只,如何只用这些物品三次将140克的盐分成50、90克各一份? 
      答案:(1)用天平把140g分成两等份,每份70g; 
      (2)用天平把其中一份70g分成两等份,每份35g; 
      (3)取其中一份35g放到天平的一端,把7g的砝码也放到这一端,再把2g的砝码放到天平的另一端.从7g砝码一端移取盐到2g砝码的一端,直到天平平衡.这时,2g砝码一端盐的量为20g.把这20g和已开始分出的未动一份70g盐放在一起,就是90g,其他的盐放在一起,就是50g.

    9. 想象你在镜子前,请问,为什么镜子中的影像可以颠倒左右,却不能颠倒上下? 
      答案:因为人的两眼在水平方向上对称。

    10. 你有两个罐子,50个红色弹球,50个蓝色弹球,随机选出一个罐子,随机选取出一个弹球放入罐子,怎么给红色弹球最大的选中机会?在你的计划中,得到红球的准确几率是多少? 
      答案:一个罐子放一个红球,另一个罐子放49个红球和50个蓝球,概率接近75%. 这是所能达到的最大概率了。 
      实际上,只要一个罐子放<50个红球,不放篮球,另一个罐子放剩下的球,拿出红球的概率就大于50%。

    11. 你有四人装药丸的罐子,每个药丸都有一定的重量,被污染的药丸是没被污染的重量+1.只称量一次,如何判断哪个罐子的药被污染了? 
      答案:先假设每颗药丸重x克,然后每个罐取分别标上1,2,3,4号.一号取一颗药丸,二号取两颗药丸,是几号就取几颗,一起称,如果是一号被污染质量为(10x+1),二号被污染质量为(10x+2),依此类推.

    12. 对一批编号为1~100 全部开关朝上开的灯进行以下操作凡是1 的倍数反方向拨一次开关2 的倍数反方向又拨一次开关3 的倍数反方向又拨一次开关。问最后为关熄状态的灯的编号。 
      答案:最后为关灯状态的有1、4、9、16、25、36、49、64、81、100共10个数,就是1~10的平方数。只有这些数有奇数个约数。

    13. 假设一张圆盘像唱机上的唱盘那样转动。这张盘一半是黑色,一半是白色。假设你有数量不限的一些颜色传感器。要想确定圆盘转动的方向,你需要在它周围摆多少个颜色传感器?它们应该被摆放在什么位置? 
      答案:2个为a,b,均放在左侧a在左上,b在左下,若a先于b变化,则顺时针,b先于a变化,则逆时针。

    14. 假设时钟到了12点。注意时针和分针重叠在一起。在一天之中,时针和分针共重叠多少次?你知道它们重叠时的具体时间吗? 
      答案:24小时,时针走2圈,分针走24圈,分针超时针22圈,重合22次. 
      (1) 00:00:00, (2) 01:05:27, (3) 02:10:54, (4) 03:16:21, (5) 04:21:49, (6) 05:27:16, (7) 06:32:43, (8) 07:38:10, (9) 08:43:38, (10) 09:49:05, (11) 10:54:32, (12) 12:00:00, (13) 13:05:27, (14) 14:10:54, (15) 15:16:21, (16) 16:21:49, (17) 17:27:16, (18) 18:32:43, (19) 19:38:10, (20) 20:43:38, (21) 21:49:05, (22) 22:54:32。

    15. 一个屋子有一个门(门是关闭的)和3盏电灯。屋外有3个开关,分别与这3盏灯相连。你可以随意操纵这些开关,可一旦你将门打开,就不能变换开关了。确定每个开关具体管哪盏灯。 
      答案:先打开一盏灯,等它亮几分钟,关上这盏再开另外一盏,然后开门进去摸一摸灯泡,发热的那个就是之前的那盏灯,亮着的就是第二盏,一直没打开过的那盏灯也就出来了,

    16. 假设你有8个球,其中一个略微重一些,但是找出这个球的惟一方法是将两个球放在天平上对比。最少要称多少次才能找出这个较重的球? (7个球找1个也是2次,分为3,3,1) 
      答案:两次。将8个球分成3组,分别有3.3.2个。将两组3个球的作为一个整体分别放到天平两端,如不平衡,将轻的一侧再分3组重复上述步骤。如平衡,将剩下的两个球分别放在天平两端。

    17. 如果你有两个桶,一个装的是红色的颜料,另一个装的是蓝色的颜料。你从蓝色颜料桶里舀一杯,倒入红色颜料桶,再从红色颜料桶里舀一杯倒入蓝颜料桶。两个桶中红蓝颜料的比例哪个更高?通过算术的方式来证明这一点。 
      答案:红桶的高,设红桶中有颜料a升,蓝桶有a升,每杯有n升,题目要求a大于n,那么:红桶中,红:蓝=a:n,蓝桶中,红:蓝=(a*n/(a+n)):(a-n+n^2/(a+n))=a*n:a^2=n:a。因为a大于n,所以,红桶中比例大于1,蓝桶中比例小于1。

     

    sql server 查询某个表被哪些存储过程调用

     

    sql server 查询某个表被哪些存储过程调用

    select distinct object_name(id) from syscomments where id in
    (select id from sysobjects where type =’P’) and text like’%TableName%’



    DataTable根据字段去重

      最近需要对datatable根据字段去重,在网上搜了很多,找到了一个方法,代码如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    public static DataTable DistinctSomeColumn(DataTable sourceTable, params string[] fieldName)
            {
                DataTable dt2 = sourceTable.Clone();
                DataView v1 = dt2.DefaultView;
                StringBuilder filter = new StringBuilder();
                foreach (DataRow row in sourceTable.Rows)
                {
                    for (int i = 0; i < fieldName.Length; i++)
                    {
                        filter.AppendFormat("{0}='{1}'", fieldName[i], row[fieldName[i]].ToString().TrimEnd());
                        if (i < fieldName.Length - 1)
                        {
                            filter.Append(" and ");
                        }
                    }
     
                    v1.RowFilter = filter.ToString();
     
                    if (v1.Count > 0)
                    {
                        filter = new StringBuilder();
                        continue;
                    }
                    dt2.Rows.Add(row.ItemArray);
                    filter = new StringBuilder();
                }
                return dt2;
            }

      经过测试,代码可以实现功能,但是其中有一点弄不明白,DataView v1 = dt2.DefaultView;这里对dt2做加入行操作,同时也能影响v1,但是经过我测试如果直接把新的一个datatable赋给dt2,则不能影响v1,还有dataview里的table属性又是什么,找了好多资料都没弄清楚,有大神解释一下吗。

     

     

     

     

    .Net Core Cors中间件解析

     

    同源策略和资源跨域共享

     1、同源策略

       同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。

     1.1、目的

       主要是为了保证用户信息的安全,防止网站窃取用户数据。假如没有同源策略,可能就会有下面这种情况的发生。用户访问两个网站A/B,并登录了A网站,A网站会在计算机本地存储Cookie或者Token等等,在访问B网站的时候,B网站就可以访问这些本地的存储信息,B网站可以使用用户的Cookie去登录A网站,那这样用户信息就被泄露了。

     1.2、限制范围   

    • Cookie、LocalStorage和indexDB无法访问(只有同源的网页才能共享Cookie)
    • DOM无法获得(父窗口和子窗口的地址是同源的才能获取子窗口的信息)
    • AJAX请求不能被发送(AJAX请求只能发送给同源的网址)

      要知道一点,这些限制其实都是浏览器做的限制。

     2、跨域资源共享

      跨域资源共享跟同源策略相反。在整个跨域通信过程中,浏览器会自动识别此次请求是否跨域,一旦发现跨域,就自动添加请求头信息(如Origin)或者自动发送一次请求方式为option的预请求。浏览器将CORS请求分为两类:简单请求和非简单请求。

     2.1、简单请求

      当浏览器的请求方式是Head、Get或者Post,并且HTTP的头信息中不会超出以下字段:

    • Accept

    • Accept-Language

    • Content-Language

    • Origin

    时,浏览器会将该请求定义为简单请求,否则就是非简单请求。当浏览器判断为简单请求后,浏览器会自动再请求报文头中加上Origin字段,表明此次请求来自的地址(协议+域名+端口)。然后服务器需要去判断是否接受这个来源的请求。如果允许服务器端返回的头部中需要有Access-Control-Allow-Origin,其值为请求时Origin字段的值或*(表示接受任意源的请求)。请求头中还会有Access-Control-Allow-Methods表示服务器允许的跨域请求的方式。Access-Control-Allow-Headers表示请求头中允许出现的字段。

     2.2、 非简单请求

       当浏览器判断为非简单请求后,会发送两次请求,首先浏览器会自动发送一个请求方式为options的请求,并在请求头中

    • 加上Access-Control-Request-Method表示下次请求的方法,
    • 加上Origin表明来源,
    • 加上Access-Control-Request-Headers表示下次请求的请求头中额外的字段。

         服务器收到请求后,需要获取这三个请求头中的值,并进行判断,确认是否允许进行跨域。如果服务器返回的请求头中没有任何CORS相关的请求头信息,浏览器会认为不通过预检,也不会进行第二次请求。

         服务器如果接受跨域并验证通过了options的请求,会返回Access-Control-Allow-Origin(表明允许跨域请求的源)、Access-Control-Allow-Methods(允许跨域请求的请求方式)、Access-Control-Allow-Headers(允许请求头中包含的额外字段)。然后浏览器才会发送真正的请求。                  

                                                  (第一次options请求)

                                               (第二次请求)

    二、服务端实现CORS

      在.Net Core Web Api中使用很简单,首先安装包Microsoft.AspNet.WebApi.Cors,在StartUp中添加下面两句

    复制代码
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddMvc();
           //添加Cors,并配置CorsPolicy 
                services.AddCors(options => options.AddPolicy("CorsTest", p => p.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()));
            }
    
            public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
           //注意UseCors()要在UseMvc()之前 app.UseCors("CorsTest"); app.UseMvc(); }
    复制代码

    在使用的时候只需要在Controller或者Action中加上特性[EnableCors("CorsTest")]

    复制代码
        [EnableCors("CorsTest")]
        public class ValuesController : Controller
        {
            private ILogger<ValuesController> _logger;
            public ValuesController(ILogger<ValuesController> logger)
            {
                _logger = logger;
            }
            [HttpGet]
            public IEnumerable<string> Get()
            {
                return new string[] { "value1", "value2" };
            }
        }
    复制代码

    现在服务端已经配置好了,现在需要通过前端跨域请求

    复制代码
    <html>
    <head>
        测试
    </head>
    <body>
        测试
    </body>
    </html>
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
    <script type="text/javascript">
        $(function () {
            $.ajax({
                type: "get",
                url: "http://localhost:7000/api/values",
                 beforeSend: function (request) {//在请求报文头中加入Authorization 目的是让请求为非简单请求
                    request.setRequestHeader("Authorization", "Bearer 071899A00D4D4C5B1C41A6B0211B9399");
                },
                success: function (result) {
                    alert(result);
                }
            }, "json");
        });
    </script>
    复制代码

    测试结果如下图:

                              (options请求)

                            (第二次请求)

     上面配置允许所有的地址请求这个接口,也可以单独配置某个地址。

    services.AddCors(options => options.AddPolicy("CorsTest", p => p.WithOrigins("http://localhost:8089")
                                                                                .AllowAnyHeader()
                                                                                .AllowAnyMethod()));

     三、解析Cors源码

      打开CORS源码,主要的是CorsMiddleware、CorsOptions、CorsPolicy、CorsPolicyBuilder、CorsResult、CorsService这几个类。

    • CorsPolicy:就是我们在Startup中的配置,如允许哪些域名可以跨域请求,允许哪些跨域请求方式,允许哪些额外的请求头,每个配置对应一个名称。
           services.AddCors(options => options.AddPolicy("CorsTest", p => p.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()));
    • CorsOptions:中包含一个字典IDictionary<string, CorsPolicy> PolicyMap,一个项目可能有过个Cors配置,所以这个CorsOptions就是通过配置名称管理这些配置的。
    • CorsPolicyBuilder:通过它来构造CorsPolicy。
    • CorsResult:是验证跨域过程得到的结果。如在第一次Options请求时,客户端发送了Origi:http://localhost:8089,服务器会返回Access-Control-Allow-Origin:http://localhost:8089,服务器验证http://localhost:8089这个域名是否允许跨域,如果允许就将“http://localhost:8089”这个值存储到CorsResult的AllowedHeaders中,在请求(第一次请求)返回的时候将这些加到HTTP请求头中。
    • CorsMiddleware:Cors中间件类,主要方法就是Invoke,每次HTTP请求都会调用这个方法。
    复制代码
         public async Task Invoke(HttpContext context)
            {//判断HTTP请求头是否有Origin,由此判断是不是跨域请求
                if (context.Request.Headers.ContainsKey(CorsConstants.Origin))
                {
                    var corsPolicy = _policy ?? await _corsPolicyProvider?.GetPolicyAsync(context, _corsPolicyName);
                    if (corsPolicy != null)
                    {
                        var accessControlRequestMethod = context.Request.Headers[CorsConstants.AccessControlRequestMethod];
                //如果是跨域请求 判断是不是第一次Options请求 if (string.Equals(context.Request.Method,CorsConstants.PreflightHttpMethod,StringComparison.OrdinalIgnoreCase) &&!StringValues.IsNullOrEmpty(accessControlRequestMethod)) {
                  //判断是否允许当前请求跨域,根据HttpContext的内容和Cors配置 得到CorsResult,然后将CorsResult的内容添加到请求头中(看下面详细解释) ApplyCorsHeaders(context, corsPolicy); context.Response.StatusCode = StatusCodes.Status204NoContent; return; } else {// 执行第二次非Options请求 context.Response.OnStarting(state => { var (httpContext, policy) = (Tuple<HttpContext, CorsPolicy>)state; try { ApplyCorsHeaders(httpContext, policy); } catch (Exception exception) { _logger.FailedToSetCorsHeaders(exception); } return Task.CompletedTask; }, Tuple.Create(context, corsPolicy)); } } } await _next(context); }      private void ApplyCorsHeaders(HttpContext context, CorsPolicy corsPolicy) {  //通过HTTP上下文请求的数据和Cors配置 得到CorsResult
            如在第一次Options请求时,客户端发送了Origi:http://localhost:8089,Access-Control-Resquest-Methods:GET
            服务器会返回Access-Control-Allow-Origin:http://localhost:8089,Access-Control-Allow-Methods:GET
            服务器验证http://localhost:8089这个域名以GET请求方式是否允许跨域,
            如果允许就将“http://localhost:8089”这个值存储到CorsResult的AllowedHeaders中
            将"GET"存储到CorsResult的AllowedMethods中 var corsResult = _corsService.EvaluatePolicy(context, corsPolicy);
            //将CorsResult中的值添加到相应头中的,返回到客户端 _corsService.ApplyResult(corsResult, context.Response); }
    复制代码

     相对来说Cors源码还是比较简单的,很容易看懂。可以自己写一个项目,然后挂上源码单步调试。

     

     

     

    分析MySQL中哪些情况下数据库索引会失效

     

      要想分析MySQL查询语句中的相关信息,如是全表查询还是部分查询,就要用到explain.

    一、explain

      用法:explain +查询语句。

    id:查询语句的序列号,上面图片中只有一个select 语句,所以只会显示一个序列号。如果有嵌套查询,如下

    select_type:表示查询类型,有以下几种

      simple: 简单的 select (没有使用 union或子查询)

      primary: 最外层的 select。

      union: 第二层,在select 之后使用了 union。

      dependent union: union 语句中的第二个select,依赖于外部子查询

      subquery: 子查询中的第一个 select

      dependent subquery: 子查询中的第一个 subquery依赖于外部的子查询

      derived: 派生表 select(from子句中的子查询)

    table:查询的表、结果集

    type:全称为"join type",意为连接类型。通俗的讲就是mysql查找引擎找到满足SQL条件的数据的方式。其值为:

    • system:系统表,表中只有一行数据
    • const:读常量,最多只会有一条记录匹配,由于是常量,实际上只须要读一次。
    • eq_ref:最多只会有一条匹配结果,一般是通过主键或唯一键索引来访问。
    • ref:对于每个来自于前面的表的行组合,所有有匹配索引值的行将从这张表中读取
    • fulltext:进行全文索引检索。
    • ref_or_null:与ref的唯一区别就是在使用索引引用的查询之外再增加一个空值的查询。
    • index_merge:查询中同时使用两个(或更多)索引,然后对索引结果进行合并,再读取表数据。
    • unique_subquery:子查询中的返回结果字段组合是主键或者唯一约束。
    • index_subquery:子查询中的返回结果字段组合是一个索引(或索引组合),但不是一个主键或唯一索引。
    • rang:索引范围扫描。
    • index:全索引扫描。
    • all:全表扫描。

      性能从上到下依次降低。

    possible_keys:可能用到的索引

    key:使用的索引

    ref: ref列显示使用哪个列或常数与key一起从表中选择行。

    rows:显示MySQL认为它执行查询时必须检查的行数。多行之间的数据相乘可以估算要处理的行数。

    Extra:额外的信息

    • Distinct:MySQL发现第1个匹配行后,停止为当前的行组合搜索更多的行。
    • Not exists:MySQL能够对查询进行LEFT JOIN优化,发现1个匹配LEFT JOIN标准的行后,不再为前面的的行组合在该表内检查更多的行。
    • range checked for each record (index map: #):MySQL没有发现好的可以使用的索引,但发现如果来自前面的表的列值已知,可能部分索引可以使用。
    • Using filesort:MySQL需要额外的一次传递,以找出如何按排序顺序检索行。
    • Using index:从只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的列信息。
    • Using temporary:为了解决查询,MySQL需要创建一个临时表来容纳结果。
    • Using where:WHERE 子句用于限制哪一个行匹配下一个表或发送到客户。
    • Using sort_union(...), Using union(...), Using intersect(...):这些函数说明如何为index_merge联接类型合并索引扫描。
    • Using index for group-by:类似于访问表的Using index方式,Using index for group-by表示MySQL发现了一个索引,可以用来查 询GROUP BY或DISTINCT查询的所有列,而不要额外搜索硬盘访问实际的表。

    二、数据库不使用索引的情况

      下面举的例子中,GudiNo、StoreId列都有单独的索引。

      2.1、like查询已 '%...'开头,以'xxx%'结尾会继续使用索引。

        下图中第一句使用的%,没有使用索引,从rows为224147,使用索引rows为1。

        

       2.2  where语句中使用 <>和 !=

        

      2.3  where语句中使用 or,但是没有把or中所有字段加上索引。

       

       这种情况,如果需要使用索引需要将or中所有的字段都加上索引。

      2.4  where语句中对字段表达式操作

       

     

      2.5  where语句中使用Not In

        

    看了别人写的文章,有说“应尽量避免在where 子句中对字段进行null 值判断,否则将导致引擎放弃使用索引而进行全表扫描”,实测没有全表扫描。

     "对于多列索引,不是使用的第一部分,则不会使用索引",实测即使多索引,没有使用第一部分,也会命中索引,没有全表扫描。

     

     

     

     

    ASP.NET Web API决跨域问题

    ASP.NET Web API决跨域问题

     

    记录最近一次的项目开发中遇到的问题和解决方式。在给移动端开放数据接口的时候,移动端开放人员反映部署到测试环境的接口调用访问出现了问题,但是在单独进行访问是可以正常的。那么,问题就来了。

    根据查询园子里大佬们的文章,了解到问题的根源。

    问题的由来:该问题的出现是因为浏览器出于安全考虑,浏览器会限制脚本中发起跨域请求(有一个项目是使用的后台做的请求,类似微信接口调用的方式,未出现改问题),JavaScript或者Cookie只能访问同域下的资源-----所谓的“同源策略”,正是这个原因导致了移动端开发人员在H5页面上使用脚本异步访问接口被浏览器阻止了。

     

    问题的解决方案:针对ASP.NET Web API 只需在web.config文件下添加相关的配置内容就可以解决了

    <system.webServer>
    <httpProtocol>
    <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*" />
    <add name="Access-Control-Allow-Headers" value="Content-Type" />
    <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
    </customHeaders>
    </httpProtocol>


    <handlers>
    <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
    <remove name="OPTIONSVerbHandler" />
    <remove name="TRACEVerbHandler" />
    <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
    </system.webServer>

     

    添加完配置后,基本上是可以解决跨域的问题了,当然还有CORS的跨域解决方案,只是还没有去了解和使用过,这里就不进行记录了。

     

    转载于:https://www.cnblogs.com/cjm123/p/9308143.html

    展开全文
  • 假设,我们现在要一个200G的InnoDBdb1. t,执行一个全扫描。当然,你要把扫描结果保存在客户端,会使用类似这样的命令: mysql -h$host -P$port -u$user -p$pwd -e "select * from db1.t

    我的主机内存只有100G,现在要全表扫描一个200G大表,会不会把DB主机的内存用光?

    逻辑备份时,可不就是做整库扫描吗?若这样就会把内存吃光,逻辑备份不是早就挂了?
    所以大表全表扫描,看起来应该没问题。这是为啥呢?

    全表扫描对server层的影响

    假设,我们现在要对一个200G的InnoDB表db1. t,执行一个全表扫描。当然,你要把扫描结果保存在客户端,会使用类似这样的命令:

    mysql -h$host -P$port -u$user -p$pwd -e 
    	"select * from db1.t" > $target_file
    

    InnoDB数据保存在主键索引上,所以全表扫描实际上是直接扫描表t的主键索引。这条查询语句由于没有其他判断条件,所以查到的每一行都可以直接放到结果集,然后返回给客户端。

    那么,这个“结果集”存在哪里呢?
    服务端无需保存一个完整结果集。取数据和发数据的流程是这样的:

    1. 获取一行,写到net_buffer。这块内存的大小是由参数net_buffer_length定义,默认16k
    2. 重复获取行,直到net_buffer写满,调用网络接口发出去
    3. 若发送成功,就清空net_buffer,然后继续取下一行,并写入net_buffer
    4. 若发送函数返回EAGAINWSAEWOULDBLOCK,就表示本地网络栈(socket send buffer)写满了,进入等待。直到网络栈重新可写,再继续发送
    • 查询结果发送流程

    可见:

    • 一个查询在发送过程中,占用的MySQL内部的内存最大就是net_buffer_length这么大,不会达到200G
    • socket send buffer 也不可能达到200G(默认定义/proc/sys/net/core/wmem_default),若socket send buffer被写满,就会暂停读数据的流程

    所以MySQL其实是“边读边发”。这意味着,若客户端接收得慢,会导致MySQL服务端由于结果发不出去,这个事务的执行时间变长。

    比如下面这个状态,就是当客户端不读socket receive buffer内容时,在服务端show processlist看到的结果。

    • 服务端发送阻塞

      若看到State一直是“Sending to client”,说明服务器端的网络栈写满了。

    若客户端使用–quick参数,会使用mysql_use_result方法:读一行处理一行。假设某业务的逻辑较复杂,每读一行数据以后要处理的逻辑若很慢,就会导致客户端要过很久才取下一行数据,可能就会出现上图结果。

    因此,对于正常的线上业务来说,若一个查询的返回结果不多,推荐使用mysql_store_result接口,直接把查询结果保存到本地内存。

    当然前提是查询返回结果不多。如果太多,因为执行了一个大查询导致客户端占用内存近20G,这种情况下就需要改用mysql_use_result接口。

    若你在自己负责维护的MySQL里看到很多个线程都处于“Sending to client”,表明你要让业务开发同学优化查询结果,并评估这么多的返回结果是否合理。

    若要快速减少处于这个状态的线程的话,可以将net_buffer_length设置更大。

    有时,实例上看到很多查询语句状态是“Sending data”,但查看网络也没什么问题,为什么Sending data要这么久?
    一个查询语句的状态变化是这样的:

    1. MySQL查询语句进入执行阶段后,先把状态设置成 Sending data
    2. 然后,发送执行结果的列相关的信息(meta data) 给客户端
    3. 再继续执行语句的流程
    4. 执行完成后,把状态设置成空字符串。

    即“Sending data”并不一定是指“正在发送数据”,而可能是处于执行器过程中的任意阶段。比如,你可以构造一个锁等待场景,就能看到Sending data状态。

    读全表被锁:

    session1 session2
    begin
    select * from t where id=1 for update
    启动事务
    select * from t lock in share mode
    (blocked)
    • Sending data状态

    可见session2是在等锁,状态显示为Sending data。

    • 仅当一个线程处于“等待客户端接收结果”的状态,才会显示"Sending to client"
    • 若显示成“Sending data”,它的意思只是“正在执行”

    所以,查询的结果是分段发给客户端,因此扫描全表,查询返回大量数据,并不会把内存打爆。

    以上是server层的处理逻辑,在InnoDB引擎里又是怎么处理?

    全表扫描对InnoDB的影响

    InnoDB内存的一个作用,是保存更新的结果,再配合redo log,避免随机写盘。

    内存的数据页是在Buffer Pool (简称为BP)管理,在WAL里BP起加速更新的作用。
    BP还能加速查询。

    • 由于WAL,当事务提交时,磁盘上的数据页是旧的,若这时马上有个查询来读该数据页,是不是要马上把redo log应用到数据页?
      不需要。因为此时,内存数据页的结果是最新的,直接读内存页即可。这时查询无需读磁盘,直接从内存取结果,速度很快。所以,Buffer Pool能加速查询。

    而BP对查询的加速效果,依赖于一个重要的指标,即:内存命中率。
    可以在show engine innodb status结果中,查看一个系统当前的BP命中率。一般情况下,一个稳定服务的线上系统,要保证响应时间符合要求的话,内存命中率要在99%以上。

    执行show engine innodb status ,可以看到“Buffer pool hit rate”字样,显示的就是当前的命中率。比如下图命中率,就是100%。

    若所有查询需要的数据页都能够直接从内存得到,那是最好的,对应命中率100%。

    InnoDB Buffer Pool的大小是由参数 innodb_buffer_pool_size确定,一般建议设置成可用物理内存的60%~80%。

    在大约十年前,单机的数据量是上百个G,而物理内存是几个G;现在虽然很多服务器都能有128G甚至更高的内存,但是单机的数据量却达到了T级别。

    所以,innodb_buffer_pool_size小于磁盘数据量很常见。若一个 Buffer Pool满了,而又要从磁盘读入一个数据页,那肯定是要淘汰一个旧数据页的。

    InnoDB内存管理

    使用的最近最少使用 (Least Recently Used, LRU)算法,淘汰最久未使用数据。

    • 基本LRU算法
      TODO

    InnoDB管理BP的LRU算法,是用链表实现的:

    • state1,链表头部是P1,表示P1是最近刚被访问过的数据页
    • 此时,一个读请求访问P3,因此变成状态2,P3被移到最前
    • 状态3表示,这次访问的数据页不存在于链表,所以需要在BP中新申请一个数据页Px,加到链表头。但由于内存已满,不能申请新内存。于是清空链表末尾Pm数据页内存,存入Px的内容,放到链表头部

    最终就是最久没有被访问的数据页Pm被淘汰。
    若此时要做一个全表扫描,会咋样?若要扫描一个200G的表,而这个表是一个历史数据表,平时没有业务访问它。

    那么,按此算法扫描,就会把当前BP里的数据全部淘汰,存入扫描过程中访问到的数据页的内容。也就是说BP里主要放的是这个历史数据表的数据。

    对于一个正在做业务服务的库,这可不行呀。你会看到,BP内存命中率急剧下降,磁盘压力增加,SQL语句响应变慢。

    所以,InnoDB不能直接使用原始的LRU。InnoDB对其进行了优化。

    • 改进的LRU算法

    InnoDB按5:3比例把链表分成New区和Old区。图中LRU_old指向的就是old区域的第一个位置,是整个链表的5/8处。即靠近链表头部的5/8是New区域,靠近链表尾部的3/8是old区域。

    改进后的LRU算法执行流程:

    1. 状态1,要访问P3,由于P3在New区,和优化前LRU一样,将其移到链表头部 =》状态2
    2. 之后要访问一个新的不存在于当前链表的数据页,这时依然是淘汰掉数据页Pm,但新插入的数据页Px,是放在LRU_old
    3. 处于old区的数据页,每次被访问的时候都要做如下判断:
      • 若该数据页在LRU链表中存在的时间超过1s,就把它移动到链表头部
      • 若该数据页在LRU链表中存在的时间短于1s,位置保持不变。1s是由参数innodb_old_blocks_time控制,默认值1000,单位ms。

    该策略,就是为了处理类似全表扫描的操作量身定制。还是扫描200G历史数据表:
    4. 扫描过程中,需要新插入的数据页,都被放到old区域
    5. 一个数据页里面有多条记录,这个数据页会被多次访问到,但由于是顺序扫描,这个数据页第一次被访问和最后一次被访问的时间间隔不会超过1秒,因此还是会被保留在old区域
    6. 再继续扫描后续的数据,之前的这个数据页之后也不会再被访问到,于是始终没有机会移到链表头部(New区),很快就会被淘汰出去。

    可以看到,这个策略最大的收益,就是在扫描这个大表的过程中,虽然也用到了BP,但对young区完全没有影响,从而保证了Buffer Pool响应正常业务的查询命中率。

    小结

    MySQL采用的是边算边发的逻辑,因此对于数据量很大的查询结果来说,不会在server端保存完整的结果集。所以,如果客户端读结果不及时,会堵住MySQL的查询过程,但是不会把内存打爆。

    而对于InnoDB引擎内部,由于有淘汰策略,大查询也不会导致内存暴涨。并且,由于InnoDB对LRU算法做了改进,冷数据的全表扫描,对Buffer Pool的影响也能做到可控。

    全表扫描还是比较耗费IO资源的,所以业务高峰期还是不能直接在线上主库执行全表扫描的。

    展开全文
  • 当我们需要一整张大的数据执行全量查询操作,比如select * from t 没有where条件,整个数据有几千万条占用内存大概 100G,而Mysql所在服务器的内存只有8G,那就不直接OOM,将整个数据库打崩了吗? 刚开始开发的...
  • > 我有一个奇怪的想法,假设用户A的id为1,用户B的id为2,保存到消息里面的id(非唯一,小的id放前面,大的id放后面)就是12,形成了点点聊天记录的唯一性,这样查最后一条聊天记录也方便,也不知道这样行不行的通,以前从...
  • 在码农的世界里,优美的应用体验,来源于程序员细节的处理以及自我要求的境界,年轻人也是忙忙碌碌的码农中一员,每天、每周,都会留下一些脚印,就是这些创作的内容,有一种执着,就是不知为什么,如果你迷茫,...
  • 想进行一个多多的数据查询 具体逻辑: 我邀请了很多会员(会员) 每个会员都会去做任务(任务) 要去查询 我邀请的所有会员 每个人的完结任务数 还有未完结任务数 这样的查询可以直接用一个sql 搞定吗 ...
  • 在码农的世界里,优美的应用体验,来源于程序员细节的处理以及自我要求的境界,年轻人也是忙忙碌碌的码农中一员,每天、每周,都会留下一些脚印,就是这些创作的内容,有一种执着,就是不知为什么,如果你迷茫,...
  • 它为什么会我这个棘手的问题有帮助呢?我为什么不取 tb_stat_daily 的用户出现的第一条数据呢?如此以来,tb_stat_daily 和 tb_stat_lord 就是 1:1 的关系了,tb_stat_daily 中的时间去和 tb_stat_lord 中的注册...
  • 韩梅梅:的啊,此时我根据电压查询OCVSOC就是12%啊。 李雷:可是我都放电到保护,不应该SOC为0了吗? 韩梅梅:此时真实电量就是12%,不信你重启解除保护继续用小电流放电还是有电的。 ........
  • 我最近的一项工作内容,就是项目软件产品的的行业需求分析,一般来说政府行业软件是和行业特征、行业法规,行业政府的办公需求,服务公众的方式、理念密切相关的。它的重心是业务逻辑的实现和数据库的规划(至少现...
  • 最近在做SQL优化中,把传统分页limit offset,size转变成内连接查询id实现,具体可见上一篇博文 关于内连接的SQL,同事提出了一些疑问,哪张表是驱动?...内连接查询时,哪张表的数据较少,哪张表就是驱动 2、
  • 状态码表

    2012-03-28 11:45:00
    每次做web开发时免不了出现各种错误,有时状态码也可以为我们提示错误原因,之前遇到的都是404、500之类的错误,但最近却遇到很多稀奇古怪的状态码,索性找出了大部分的状态码表,方便查询 当服务器客户请求进行...
  • 项目开发之查询优化

    2018-04-02 16:08:03
    怎么优化查询速度对于优化查询速度,有一个简单且实用的方式就是对数据库添加索引。而关于添加索引又有哪些问题呢?1、对于一张应该选择那些字段作为索引呢?一般来说选择where、on、group by、order by后面的...
  • MySQL大查询的问题

    2021-01-19 20:01:16
    我们经常会遇到这样的问题,我的主机内存只有 100G,现在要一个 200G 的大做全扫描,会不会把数据库主机的内存用光了?这个问题确实值得担心,被系统 OOM(out of memory)可不是闹着玩的。 但是,反过来想想...
  • 我也不知道这几张谁建的, 俺也不敢说,俺也不敢问, 刚进公司实习,同事安排我写SQL语句, 我十分蛋疼的写到自闭想离开了, ... 最终我提交的就是这句了,请问大佬,对吗?如果不对的话要怎么写?
  • 在用hibernate本身的级联查询会把之前的子已经删除的数据也检索出来. 求最好的解决方法. [b]问题补充:[/b] 如果是一一呢?怎么解决/ 您这上面只有集合进行 [b]问题补充:[/b] 没有其他方法了吗?把one-to...
  • 主机内存只有100G时,现在要一个200G的大做全扫描,会不会把数据库主机的内存用光了? 这个问题确实值得担心,被系统OOM(out of memory)可不是闹着玩的 但是,反过来想想,逻辑备份的时候,可不就是做整库扫描...
  • GROUPBY只能存在的数据分组,count为零,就是没有数据存在,据我所知是没有办法的,sql很久没写了,你等别人回答吧 先明白innerjoin跟leftjoin查询在Linq中的区别。 循环对照下被,既然你说想把数量为零得分组取...
  • 数据库:一一,一多,多

    千次阅读 2018-08-16 10:08:11
    一:就是说A中的一条记录对应着B的一条记录。大家可能会觉得这不是变得复杂了吗?其实不然,如果,当一张的字段过于太多,而很多字段可能只有在某些情况下,才会使用到,这时也可以考虑使用一一设计。 ...
  • 所以在这里请教下前辈,你们这样的情况怎么设计(假设数据库设计是没问题的,就是10个字段,而要在前台用户部分信息列表),书上提到的JDO(Java Data Object)我也不知道干嘛用的, 和这个有关系吗?...
  • 一直不明白垂直分表,就是把一张的字段分到两张里面,弄一个关联字段,再用left join查询吗?
  • 我在网上查询有关这个问题的资料,我产生了疑惑,有了想法,但我不知道我的想法不对,因为我没有看过相关MySQL的书籍,我只是跟着网站在学习: 当在数据的 已有数据的字段 后增添新的字段,这时候会默认你...

空空如也

空空如也

1 2 3 4 5 ... 9
收藏数 175
精华内容 70
关键字:

查询就是表对吗