深入 PHP 面向对象、模式与实践

  1. clone需要操作原对象,但又不想影响原对象.

    基本数据类型和数组都为真复制,即为真副本,当属性为对象时,为假复制,改变副本仍会影响原对象.解决方案:

    __clone 在clone前自动触发,可以执行一些在备份前的属性操作.
  2. &传递引用

    方法引用传递,改变源对象

  3. static延迟静态绑定

    应用场景:Dog类和Person类都需要一个返回实例化的方法,Dog类和Person类都继承于Animal抽象类.

  4. 拦截器
    1. __get($property) ,访问未定义的属性时调用.
    2. __set($property,$value) ,给未定义的属性赋值时被调用.
    3. __isset($property) ,对未定义属性调用isset()方法时调用.
    4. __unset($property) ,对未定义属性调用unset()方法时调用.
    5. __call($method,$arg_array),调用未定义方法时调用.

      __call很有用,但要慎用,因为太灵活.

      应用场景:有一个专门打印Person类信息的Person_Writer类,如果通过Person类调用Person_Writer类.

  5. 回调函数应用场景: 3个类, Product类 , Product_Sale类 , Product_Totalizer类 ,要实现:当卖出Product总共价格超过指定金额时,输出警告.

  6. get_class() 和 instanceofget_class(类) 用于判断是否精准等于类名;

    instanceof 可以判断是否其本身或继承于某父类.

  7. 类中的方法和类中的属性get_class_methods(‘类名’) :获取类中所有方法.

    get_class_vars(‘类名’) :获取类中所有public参数;

  8. 反射API

2 模式

2.1 组合

问题:课堂类被演讲类和研讨会类继承着.但是演讲类和研讨类都要实现一次性计费和上N次课计费的方法.和输出计算的方式.

解决方案1: 在课堂类中添加计算一次性付费的方法,上N次课的计费方法和输出计算方式的方法.

解决方案2: 运用组合,将处理计费和输出计算方式单独封装为一个计费策略类.

组合既委托.同级委托.

继承既父子关系.

3 生成对象

3.1 单例模式

确保系统中只有唯一一个用例.例如系统配置文件.

重点

1: 构造方法私有.

2: 类本身包含自己的实例化属性.

3.2 工厂模式

通过一个父类,生产处多个不同功能的子类.

特点:产品方(新浪微博)和需求方(显示新浪微博)一一对应.

问题:印象笔记中,来源可能为新浪微博,或者开发者头条,在印象笔记显示的时候,两者的页眉和页尾是不一样的.

3.3 抽象模式

RLGL!!!.印象笔记不只要显示新浪微博内容!!!还要显示我的新浪账号,还要该微博啊

!!卧槽

~憋着急,吻我.

工厂模式主要用于生产一一对应的产品方和需求方,而抽象模式要做的是一个需求方(印象笔记_显示新浪微博),要多个工厂(把需求方抽象为多个需求方),例如提供新浪内容的工厂,提供新浪账号的工厂.提供微博内容的评论的工厂等.

代码:

3.4 平行模式

当使用工厂/抽象模式必须要制定具体的创建者(需求方).

平行模式和抽象模式的模型图一致,但代码实现不一样.

抽象模式中父类均为抽象类,而平行模式中,所以类都为普通类,方便父类的实例化.

在这里列出显示印象笔记类的实现代码

其实大家可以发现,原型模式只不过只在最顶层类中包装了一下各组件子类而已,然而这样可以轻松的组合他们,例如实现一个显示新浪微博内容,但要显示开发者头条账号的需求?

4 使用对象

4.1 组合模式

组合模式,可以理解为单一对象管理组合对象(聚合组件),最终组合体下的各个组合部件最好类型一致.不然特殊性越多,需要判断就越多.

假设捶背男,洗脚男,洗发男,用来服务一个人(妹子).

假设妹子的几个部位可用的服务男均为无限个.

这是一个很理想的组合模式,在现实情况,我们使用组合模式,可能不得不创建多种类型的洗脚男,需要添加许多判断条件.

4.2 装饰模式

装饰模式,首先洗脚男,洗发男,捶背男都是人,但是如果,一个男的又捶背,又洗发,这怎么玩?. add_man 两次?这不科学吧,来给这些男的装饰一下吧~

装饰模式,既(组合+继承),基类方法一定要尽量少,不然子类可能有它不该有的方法.直接类继承,她只可能是一种形态,而她的多种形态可能一并拥有的时候,应该运用组合.

继承即单一多态,组合既多种多态.

这个例子中,你可以添加女,然后把装饰男类型改为装饰通用类型,但每个get_well()都要多一个判断是男还是女(如果给予的舒服程度不一样).

这只是确保不可能出现在 男 , 女 之外的第三种人,如果基类为动物,给予服务的可能是鸡,鹅,鸭,那么装饰类型应该运用工厂模式,动物形态和装饰形态一一对应.方便拓展.

除了服务类型,服务男的样子也很重要,这就多了一种装饰,现在有 装饰男类型 和 相貌男类型 ,这种情况怎么破,其实类似.

4.3 外观模式

即给外部系统提供清晰接口

例如当Model层写得很混乱,但是里面的方法还能用,那我们的Controller层应该列举一些清晰的访问方法来供View层访问.外观模式,强调的是清晰的访问接口.

5 执行任务

5.1 策略模式

给类添加功能.对象要显式的调用它.

继续刚才的洗脚男和人的故事吧…你丫的爽完了要给钱吧?支付宝?微信?现金?

这个付款方式有多种,实现方法不应该放在 人 类中,而是应该委托给别的类

5.2 观察者模式

当被观察者发生变化,观察者需要被通知.

当数据发生变化,页面需要被通知.

使用步骤:

  1. 观察者加载到被观察者中.
  2. 被观察者通知观察者.

例如登陆类(被观察)状态改变,要出发邮件系统和日志系统(观察者)

PHP有内置的SPL实现上述的观察者模式.

5.3 访问者模式

问题: 在一个军队中,有很多军队,军队下面可能包含军队/步兵/弓箭手,这时我们要显示一个军队的战斗力/需要粮食的各级分配?(遍历对象并设置显示方法).怎么办?.解决办法是军队还是保存自己的基本信息,设置一个访问者,访问者包含总战斗力方法和总粮食的方法.

访问者

被访问者

调用

输出

5.4 命令模式

例子为Web页面的login和feed_back,假如都需要使用ajax提交,那么问题来了,将表单封装好提交上去,得到了返回结果.如何根据返回结果跳转不同的页面?.

有些同学就说了,login和feed_back各自写一个方法憋,提交的时候调用各自的方法.

然后再来个logout命令..增加..删除..命令怎么办..

命令模式比较适合 命令执行 例如登陆,反馈等简单只需要判断是否成功的任务

命令:

部署命令的调用者

客户端

使用

高可用集群的解决方案

高可用性即HA(High Availability)指的是通过尽量缩短因日常维护操作(计划)和突发的系统崩溃(非计划)所导致的停机时间,以提高系统和应用的可用性。

计算机系统的高可用在不同的层面上有不同的表现:

(1)网络高可用

由于网络存储的快速发展,网络冗余技术被不断提升,提高IT系统的高可用性的关键应用就是网络高可用性,网络高可用性与网络高可靠性是有区别的,网络高可用性是通过匹配冗余的网络设备实现网络设备的冗余,达到高可用的目的。

比如冗余的交换机,冗余的路由器等

(2)服务器高可用

服务器高可用主要使用的是服务器集群软件或高可用软件来实现。

(3)存储高可用

使用软件或硬件技术实现存储的高度可用性。其主要技术指标是存储切换功能,数据复制功能,数据快照功能等。当一台存储出现故障时,另一台备用的存储可以快速切换,达一存储不停机的目的。

MongoDB的高可用集群配置

高可用集群,即High Availability Cluster,简称HA Cluster。

集群(cluster)就是一组计算机,它们作为一个整体向用户提供一组网络资源。

这些单个的计算机系统 就是集群的节点(node)。

搭建高可用集群需要合理的配置多台计算机之间的角色,数据恢复,一致性等,主要有以下几种方式:

(1)主从方式 (非对称方式)

主机工作,备机处于监控准备状况;当主机宕机时,备机接管主机的一切工作,待主机恢复正常后,按使用者的设定以自动或手动方式将服务切换到主机上运行,数据的一致性通过共享存储系统解决。

(2)双机双工方式(互备互援)

两台主机同时运行各自的服务工作且相互监测情况,当任一台主机宕机时,另一台主机立即接管它的一切工作,保证工作实时,应用服务系统的关键数据存放在共享存储系统中。

(3)集群工作方式(多服务器互备方式)

多台主机一起工作,各自运行一个或几个服务,各为服务定义一个或多个备用主机,当某个主机故障时,运行在其上的服务就可以被其它主机接管。

MongoDB集群配置的实践也遵循了这几个方案,主要有主从结构,副本集方式和Sharding分片方式。

Master-Slave主从结构

主从架构一般用于备份或者做读写分离。一般有一主一从设计和一主多从设计。

由两种角色构成:

(1)主(Master)

可读可写,当数据有修改的时候,会将oplog同步到所有连接的salve上去。

(2)从(Slave)

只读不可写,自动从Master同步数据。

特别的,对于Mongodb来说,并不推荐使用Master-Slave架构,因为Master-Slave其中Master宕机后不能自动恢复,推荐使用Replica Set,后面会有介绍,除非Replica的节点数超过50,才需要使用Master-Slave架构,正常情况是不可能用那么多节点的。

还有一点,Master-Slave不支持链式结构,Slave只能直接连接Master。Redis的Master-Slave支持链式结构,Slave可以连接Slave,成为Slave的Slave。

Relica Set副本集方式

Mongodb的Replica Set即副本集方式主要有两个目的,一个是数据冗余做故障恢复使用,当发生硬件故障或者其它原因造成的宕机时,可以使用副本进行恢复。

另一个是做读写分离,读的请求分流到副本上,减轻主(Primary)的读压力。

1.Primary和Secondary搭建的Replica Set

Replica Set是mongod的实例集合,它们有着同样的数据内容。包含三类角色:

(1)主节点(Primary)

接收所有的写请求,然后把修改同步到所有Secondary。一个Replica Set只能有一个Primary节点,当Primary挂掉后,其他Secondary或者Arbiter节点会重新选举出来一个主节点。默认读请求也是发到Primary节点处理的,需要转发到Secondary需要客户端修改一下连接配置。

(2)副本节点(Secondary)

与主节点保持同样的数据集。当主节点挂掉的时候,参与选主。

(3)仲裁者(Arbiter)

不保有数据,不参与选主,只进行选主投票。使用Arbiter可以减轻数据存储的硬件需求,Arbiter跑起来几乎没什么大的硬件资源需求,但重要的一点是,在生产环境下它和其他数据节点不要部署在同一台机器上。

注意,一个自动failover的Replica Set节点数必须为奇数,目的是选主投票的时候要有一个大多数才能进行选主决策。

(4)选主过程

其中Secondary宕机,不受影响,若Primary宕机,会进行重新选主:

2.使用Arbiter搭建Replica Set

偶数个数据节点,加一个Arbiter构成的Replica Set方式:

Sharding分片技术

当数据量比较大的时候,我们需要把数据分片运行在不同的机器中,以降低CPU、内存和IO的压力,Sharding就是数据库分片技术。

MongoDB分片技术类似MySQL的水平切分和垂直切分,数据库主要由两种方式做Sharding:垂直扩展和横向切分。

垂直扩展的方式就是进行集群扩展,添加更多的CPU,内存,磁盘空间等。

横向切分则是通过数据分片的方式,通过集群统一提供服务:

(1)MongoDB的Sharding架构

(2)MongoDB分片架构中的角色

A.数据分片(Shards)

用来保存数据,保证数据的高可用性和一致性。可以是一个单独的 mongod 实例,也可以是一个副本集。

在生产环境下Shard一般是一个Replica Set,以防止该数据片的单点故障。所有Shard中有一个PrimaryShard,里面包含未进行划分的数据集合:

B.查询路由(Query Routers)

路由就是mongos的实例,客户端直接连接mongos,由mongos把读写请求路由到指定的Shard上去。

一个Sharding集群,可以有一个mongos,也可以有多mongos以减轻客户端请求的压力。

C.配置服务器(Config servers)

保存集群的元数据(metadata),包含各个Shard的路由规则。

参考:

百度百科-高可用集群

MongoDB 教程

正则表达式-思维导图

  • 语法结构
  • 字符
    • 普通字符:字母、数字、汉字、下划线,匹配与之相同的一个字符
    • 简单转义字符:\n(换行),\t(制表),\\(\本身)和 \^…(\^等有特殊作用的符号如要匹配自己的话要用转义)
    • 标准字符集合
      注意区分大小写,大写是相反的意思,匹配相反是不匹配

      • \d
        任意一个数字,0~9
      • \w
        任意一个字母、数字、汉字或下划线,A~Z、a~z、0~9、_和任意一个汉字
      • \s
        任意空白符,包括空格、制表符、换行符
      • .
        小数点可以匹配任意一个字符,换行除外(如果要匹配包括”\n”在内的所有字符,一般用[\s\S])
    • 自定义字符集合
      [ ]方括号匹配方式,能够匹配方括号中的任意一个字符,^表示取反

      • [ab5@]
        匹配”a”或”b”或”5″或”@”
      • [^abc]
        匹配a、b、c之外的任意字符
      • [f-k]
        匹配“f”到”k”之间的字符
      • [^A-F0-3]
        匹配“A”-“F”,”0″-“3″之外的任意一个字符
  • 量词(Quantifier)
    修饰前面的一个表达式,如果要修饰多个表达式,就用( )把表达式包起来

    • {n}
      表达式重复n次​
    • {m,n}
      表达式至少重复m次,最多重复n次

      • 贪婪模式 (默认)
        匹配符合的最长的字符串
      • 非贪婪模式 (在量词后面加 ? 例:{m,n}? )
        匹配符合的最短的字符串
    • {m,}
      表达式至少重复m次

    • 匹配表达式0或1次,相当于{0,1}
    • +
      表达式至少出现一次,相当于{1,}
    • *
      表达式不出现或出现任意次,相当于{0,}
  • 字符边界
    零宽:匹配的不是字符而是位置,符合某种条件的位置

    • ^
      与字符串开始的地方匹配
    • $
      与字符串结束的地方匹配
    • \b
      匹配一个单词的边界,当前位置前面的字符和后面的字符不全是\w
  • 预搜索(零宽断言、环视)
    零宽:匹配的不是字符而是位置,符合某种条件的位置

    • (?=exp)
      断言自身出现的位置的后面能匹配表达式exp
    • (?!exp)
      断言自身出现的位置的后面不能匹配表达式exp
    • (?<=exp)
      断言自身出现的位置的前面能匹配表达式exp
    • (?<!exp)
      断言自身出现的位置的前面不能匹配表达式exp
  • 匹配模式
    对文本的处理方式

    • IGNORECASE 忽略大小写模式
      • 匹配时忽略大小写
      • 默认是区分大小写的
    • SINGLELINE 单行模式
      • 整个文本看作一个字符串,只有一个开头一个结尾
      • 使小数点”.”可以匹配包含换行符(\n)在内的任意字符
    • MULTILINE 多行模式
      • 每行都是一个字符串
      • 在多行模式下,如果需要仅匹配字符串开始和结束位置,可以使用\A和\Z
  • 选择符和分组
    分支结构、捕获组合非捕获组

    • | 分支结构​
      左右表达式之间“或”关系,匹配左边或右边
    • ( ) 捕获组
      • (1)、在被修饰匹配次数的时候,括号中的表达式可以作为整体被修饰
      • (2)、取匹配结果的时候,括号中的表达式匹配到的内容可以被单独得到
      • (3)、每一对括号会分配一个编号,使用()的捕获根据左括号的顺序从1开始自动编号。捕获编号为零的第一个捕获是整个正则表达式模式匹配的文本
      • 反向引用:通过反向引用,可以对分组已捕获的字符串进行引用。
    • (?:Expression) 非捕获组
      一些表达式中,不得不使用(),但又不需要保存()中子表达式匹配的内容,这时可以用非捕获组来抵消()带来的副作用。\

原文链接

给站点加上HTTPS

免费获取证书的地方不少,这次我领的腾讯云的. 链接:https://cloud.tencent.com/product/ssl

按照流程去申请通过之后,列表里会给你展示出来.这个证书是按照给你颁发的.也就是你项目多就每个都申请一遍.时常是1年.

通过会有一个文件给你,下载下来里面会有文件.包含:Apache/IIS/Nginx/Tomcat.

我们这里是php,里面的文件上传到服务器上.之后配置Nginx.那你肯定知压缩包里用的是哪个吧.

官方提供一个配置: https://cloud.tencent.com/document/product/400/4143

配置完成后,先用bin/nginx –t来测试下配置是否有误,正确无误的话,重启nginx。就可以使 https://www.domain.com 来访问了。

对于用户不知道网站可以进行https访问的情况下,让服务器自动把http的请求重定向到https。
在服务器这边的话配置的话,可以在页面里加js脚本,也可以在后端程序里写重定向,当然也可以在web服务器来实现跳转。Nginx是支持rewrite的(只要在编译的时候没有去掉pcre)在http的server里增加rewrite ^(.*) https://$host$1 permanent;这样就可以实现80进来的请求,重定向为https了(注意这是配置80的别写错地方)。

旅游

6月开始已经离职,由于家人都已经去了重庆.那我这次也要离开北京.来一趟长途旅行.

目的地: 重庆市-成都市-昆明市.

景点就不一一赘述,印象最好的还是昆明的公园.

00:00/00:00

MySQL Explain笔记

原文

一、语法

例如:

二、explain输出解释

1 id

SQL执行的顺利的标识,SQL从大到小的执行。

例如:

很显然这条SQL是从里向外的执行,就是从 <span class="hljs-attr">id</span>=<span class="hljs-number">3</span> 向上执行。

2 select_type

就是 <span class="hljs-keyword">select</span>类型,可以有以下几种

(1)SIMPLE

简单 <span class="hljs-keyword">SELECT</span>(不使用 UNION子查询等)。

例如:

(2)PRIMARY

就是最外层的 <span class="hljs-keyword">select</span>

例如:

(3)UNION

UNION中的第二个或后面的 <span class="hljs-keyword">SELECT</span>语句。

例如

(4)DEPENDENT UNION

UNION中的第二个或后面的 <span class="hljs-keyword">SELECT</span>语句,取决于外面的查询。

(4)UNION RESULT

UNION的结果。

(5)SUBQUERY

子查询中的第一个 <span class="hljs-keyword">SELECT</span>

(6)  DEPENDENT SUBQUERY

子查询中的第一个 <span class="hljs-keyword">SELECT</span>,取决于外面的查询。

(7)DERIVED

派生表的SELECTFROM子句的子查询)。

3 table

显示这一行的数据是关于哪张表的。
有时不是真实的表名字,看到的是 derivedxx是个数字,是第几步执行的结果)。

4 type

这列很重要,显示了连接使用了哪种类别,有无使用索引。
从最好到最差的连接类型为 <span class="hljs-keyword">const</span>eq_reg<span class="hljs-keyword">ref</span>range<span class="hljs-keyword">index</span>ALL

(1)system

这是 <span class="hljs-keyword">const</span>联接类型的一个特例,表仅有一行满足条件。

如下( t3表上的 <span class="hljs-keyword">id</span><span class="hljs-attribute">primary</span> key

(2)const

表最多有一个匹配行,它将在查询开始时被读取。

因为仅有一行,在这行的列值可被优化器剩余部分认为是常数。

<span class="hljs-keyword">const</span>表很快,因为它们只读取一次!

<span class="hljs-keyword">const</span>用于用常数值比较 <span class="hljs-attribute">PRIMARY</span> KEYUNIQUE索引的所有部分时。

在下面的查询中, tbl_name可以用于 <span class="hljs-keyword">const</span>表:

例如:

(3) eq_ref

对于每个来自于前面的表的行组合,从该表中读取一行。

这可能是最好的联接类型,除了 <span class="hljs-keyword">const</span>类型。

它用在一个索引的所有部分被联接使用并且索引是 UNIQUE<span class="hljs-attribute">PRIMARY</span> KEY

eq_ref可以用于使用 = 操作符比较的带索引的列。

比较值可以为 常量或一个使用在该表前面所读取的表的列的表达式。

在下面的例子中,MySQL可以使用 eq_ref联接来处理 ref_tables

例如

(4)ref

对于每个来自于前面的表的行组合,所有有匹配索引值的行将从这张表中读取。

如果联接只使用键的最左边的前缀,或如果键不是 UNIQUE<span class="hljs-attribute">PRIMARY</span> KEY(换句话说,如果联接不能基于关键字选择单个行的话),则使用 <span class="hljs-keyword">ref</span>

如果使用的键仅仅匹配少量行,该联接类型是不错的。

<span class="hljs-keyword">ref</span>可以用于使用 =<span class="hljs-section">&lt;=&gt;</span>操作符的带索引的列。

在下面的例子中,MySQL可以使用 <span class="hljs-keyword">ref</span>联接来处理 ref_tables

例如:

(5)  ref_or_null

该联接类型如同 <span class="hljs-keyword">ref</span>,但是添加了MySQL可以专门搜索包含 <span class="hljs-literal">NULL</span>值的行。

在解决子查询中经常使用该联接类型的优化。

在下面的例子中,MySQL可以使用 ref_or_null联接来处理 ref_tables

(6) index_merge

该联接类型表示使用了索引合并优化方法。

在这种情况下, key列包含了使用的索引的清单, key_len包含了使用的索引的最长的关键元素。

例如:

(7) unique_subquery

该类型替换了下面形式的 IN子查询的 <span class="hljs-keyword">ref</span>

unique_subquery是一个索引查找函数,可以完全替换子查询,效率更高。

(8)index_subquery

该联接类型类似于 unique_subquery,可以替换 IN子查询。

但只适合下列形式的子查询中的非唯一索引:

(9)range

只检索给定范围的行,使用一个索引来选择行。

key列显示使用了哪个索引。

key_len包含所使用索引的最长关键元素。

在该类型中 <span class="hljs-keyword">ref</span>列为 <span class="hljs-literal">NULL</span>

当使用 =<span class="hljs-section">&lt;&gt;</span>&gt;&gt;=&lt;&lt;=IS <span class="hljs-literal">NULL</span><span class="hljs-section">&lt;=&gt;</span>BETWEEN或者 IN操作符,用常量比较关键字列时,可以使用 range

(10)index

该联接类型与 ALL相同,除了只有索引树被扫描。

这通常比 ALL快,因为索引文件通常比数据文件小。

当查询只使用作为单索引一部分的列时,MySQL可以使用该联接类型。

(11) ALL

对于每个来自于先前的表的行组合,进行完整的表扫描。

如果表是第一个没标记 <span class="hljs-keyword">const</span>的表,这通常不好,并且通常在它情况下很差。

通常可以增加更多的索引而不要使用 ALL,使得行能基于前面的表中的常数值或列值被检索出。

5 possible_keys

possible_keys列指出MySQL能使用哪个索引在该表中找到行。

注意,该列完全独立于 <span class="hljs-keyword">EXPLAIN</span>输出所示的表的次序。

这意味着在 possible_keys中的某些键,实际上不能按生成的表次序使用。

如果该列是 <span class="hljs-literal">NULL</span>,则没有相关的索引。

在这种情况下,可以通过检查 WHERE子句,看是否它引用某些列,或适合索引的列来提高你的查询性能。

如果是这样,创造一个适当的索引并且再次用 <span class="hljs-keyword">EXPLAIN</span>检查查询

6 key

key列显示MySQL实际决定使用的键(索引)。

如果没有选择索引,键是 <span class="hljs-literal">NULL</span>

要想强制 MySQL使用、或忽视 possible_keys列中的索引,在查询中使用 <span class="hljs-attribute">FORCE</span> INDEX<span class="hljs-keyword">USE</span> <span class="hljs-keyword">INDEX</span>或者 <span class="hljs-attribute">IGNORE</span> INDEX

7 key_len

key_len列显示MySQL决定使用的键长度。

如果键是 <span class="hljs-literal">NULL</span>,则长度为 <span class="hljs-literal">NULL</span>

使用的索引的长度。在不损失精确性的情况下,长度越短越好

8 ref

<span class="hljs-keyword">ref</span>列显示使用哪个列,或常数与 key一起从表中选择行。

9 rows

rows列显示MySQL认为它执行查询时必须检查的行数。

10 Extra

该列包含MySQL解决查询的详细信息,下面详细介绍。

(1)Distinct

一旦MYSQL找到了与行相联合匹配的行,就不再搜索了

(2)Not exists

MYSQL优化了 <span class="hljs-attribute">LEFT</span> JOIN,一旦它找到了匹配 <span class="hljs-attribute">LEFT</span> JOIN标准的行,就不再搜索了

(3)Range checked for each

Record(index map:#)

没有找到理想的索引,因此对于从前面表中来的每一个行组合,MYSQL检查使用哪个索引,并用它来从表中返回行。

这是使用索引的最慢的连接之一。

4)Using filesort

看到这个的时候,查询就需要优化了。

MYSQL需要进行额外的步骤,来发现如何对返回的行排序。

它根据连接类型、以及存储排序键值、和匹配条件的全部行的行指针来排序全部行。

(5)Using index

列数据是从仅仅使用了索引中的信息,而没有读取实际的行动的表返回的。

这发生在,对表的全部的请求列都是同一个索引的部分的时候。

(6)Using temporary

看到这个的时候,查询需要优化了。

这里,MYSQL需要创建一个临时表来存储结果。

这通常发生在对不同的列集进行 <span class="hljs-attribute"><span class="hljs-nomarkup">ORDER</span></span> BY上,而不是 <span class="hljs-attribute">GROUP</span> BY上。

(7)Using where
使用了 WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。

如果不想返回表中的全部行,并且连接类型 ALL<span class="hljs-keyword">index</span>,这就会发生,或者是查询有问题。

ubuntu 16.04 下重置 MySQL 5.7 的密码(忘记密码)

编辑mysql的配置文件/etc/mysql/mysql.conf.d/mysqld.cnf,在[mysqld]段下加入一行“skip-grant-tables”

编辑完保存退出.

空密码进mysql

把 /etc/mysql/mysql.conf.d/mysqld.cnf,把你加入的那一行“skip-grant-tables”注释或删除掉。

之后你就可以用新密码登陆了.

完结!

PHP的基本GC概念

PHP语言同其他语言一样,具有垃圾回收机制。那么今天我们要为大家讲解的内容就是关于PHP垃圾回收机制的相关问题。希望对大家有所帮助。

PHP strtotime应用经验之谈PHP memory_get_usage()管理内存PHP unset全局变量运用问题详解PHP unset()函数销毁变量教你快速实现PHP全站权限验证一、PHP 垃圾回收机制(Garbage Collector 简称GC) 在PHP中,没有任何变量指向这个对象时,这个对象就成为垃圾。PHP会将其在内存中销毁;这是PHP的GC垃圾处理机制,防止内存溢出。当一个PHP线程结束时,当前占用的所有内存空间都会被销毁,当前程序中所有对象同时被销毁。GC进程一般都跟着每起一个SESSION而开始运行的.gc目的是为了在session文件过期以后自动销毁删除这些文件.二、__destruct /unset __destruct() 析构函数,是在垃圾对象被回收时执行。

unset 销毁的是指向对象的变量,而不是这个对象。三、 Session 与PHP垃圾回收机制由于PHP的工作机制,它并没有一个daemon线程来定期的扫描Session信息并判断其是否失效,当一个有效的请求发生时,PHP 会根据全局变量 session.gc_probability和session.gc_divisor的值,来决定是否启用一个GC。 在默认情况下,session.gc_probability=1, session.gc_divisor =100也就是说有1%的可能性启动GC(也就是说100个请求中只有一个gc会伴随100个中的某个请求而启动).

PHP垃圾回收机制的工作就是扫描所有的Session信息,用当前时间减去session最后修改的时间,同session.gc_maxlifetime参数进行比较,如果生存时间超过gc_maxlifetime(默认24分钟),就将该session删除。

但是,如果你Web服务器有多个站点,多个站点时,GC处理session可能会出现意想不到的结果,原因就是:GC在工作时,并不会区分不同站点的session.那么这个时候怎么解决呢?

  • 修改session.save_path,或使用session_save_path()让每个站点的session保存到一个专用目录,
  • 提供GC的启动率,自然,PHP垃圾回收机制的启动率提高,系统的性能也会相应减低,不推荐。
  • 在代码中判断当前session的生存时间,利用session_destroy()删除。

引用计数基本知识

每个php变量存在一个叫做”zval”的变量容器中.一个zval变量容器,除了包含变量的类型和值,还包括两个字节的额外信息.

第一个是”is_ref”,是个bool值,用来标识这个变量是否是属于引用集合(reference set).通过这个字节,php引擎才能把普通变量和引用变量区分开.由于php允许用户通过使用&来使用自定义引用,zval变量容器中还有一个内部引用计数机制,来优化内存使用.第二个额外字节是”refcount”,用来表示指向这个zval变量容器的变量(也称符号即symbol)个数.

当一个变量被赋常量值时,就会生成一个zval变量容器,如下例所示:

[/crayon]
在上例中,新的变量是a,是在当前作用域中生成的.并且生成了类型为string和值为”new string”的变量容器.在额外的两个字节信息中,”is_ref”被默认设置为false,因为没有任何自定义的引用生成.”refcount”被设定为1,因为这里只有一个变量使用这个变量容器.调用xdebug查看一下变量内容:

[/crayon]
以上代码会输出:

[/crayon]
对变量a增加一个引用计数

[/crayon]
以上代码会输出:

[/crayon]
这时,引用次数是2,因为同一变量容器被变量a和变量b关联.当没必要时,php不会去复制已生成的变量容器.变量容器在”refcount”变成0时就被销毁.当任何关联到某个变量容易的变量离开它的作用域(比如:函数执行结束),或者对变量调用了unset()函数,”refcount”就会减1,下面例子就能说明:

[/crayon]
以上代码会输出:

[/crayon]
如果我们现在执行unset($a),$包含的类型和值的这个容器就会从内存删除

复合类型(compound types)

当考虑像array和object这样的复合类型时,事情会稍微有些复杂.与标量(scalar)类型的值不同,array和object类型的变量把它们的成员或属性存在自己的符号表中.这意味着下面的例子将生成三个zval变量容器

[/crayon]
以上代码输出:

[/crayon]
这三个zval变量容器是:a,meaning,number.增加和减少refcount的规则和上面提到的一样特例,添加数组本身作为数组元素时:

[/crayon]
以上代码输出的结果:

[/crayon]
可以看到数组a和数组本身元素a[1]指向的变量容器refcount为2

当对数组$a调用unset函数时,$a的refcount变为1,发生了内存泄漏

清理变量容器的问题。

尽管不再有某个作用域中的任何符号指向这个结构(就是变量容器),由于数组元素”1″仍然指向数组本身,所以这个容器不能被消除.因为没有另外的符号指向它,用户没有办法清除这个结构,结果就会导致内存泄漏.庆幸的是,php将在请求结束时清除这个数据结构,但是php清除前,将耗费不少内存空间。

回收周期

5.3.0PHP使用了新的同步周期回收算法,来处理上面所说的内存泄漏问题

首先,我们先要建立一些基本规则:

如果一个引用计数增加,它将继续被使用,当然就不再垃圾中.如果引用技术减少到零,所在的变量容器将被清除(free).就是说,仅仅在引用计数减少到非零值时,才会产生垃圾周期(grabage cycle).其次,在一个垃圾周期中,通过检查引用计数是否减1,并且检查哪些变量容器的引用次数是零,来发现哪部分是垃圾。

为避免不得不检查所有引用计数可能减少的垃圾周期,这个算法把所有可能根(possible roots 都是zval变量容器),放在根缓冲区(root buffer)中(用紫色标记),这样可以同时确保每个可能的垃圾根(possible garbage root)在缓冲区只出现一次.仅仅在根缓冲区满了时,才对缓冲区内部所有不同的变量容器执行垃圾回收操作。

原文链接

PHP数组占用内存分析

下面的做法会占用多大的内存?

[/crayon]

测试

[/crayon]
上面运行输出的结果如下:

[/crayon]
可见数组占用的内存远大于正常分配的内容

原理

在PHP中都使用long类型来代表数字,没有使用int类型。大家都明白PHP是一种弱类型的语言,它不会去区分变量的类型,没有int float char *之类的概念。我们看看php在zend里面存储的变量,PHP中每个变量都有对应的 zval,Zval结构体定义在Zend/zend.h里面,其结构:

[/crayon]
PHP使用一种UNION结构来存储变量的值,即zvalue_value 是一个union,UNION变量所占用的内存是由最大成员数据空间决定。

[/crayon]
最大成员数据空间是struct str,指针占*val用4字节,INT占用4字节,共8字节。struct zval占用的空间为8+4+1+1 = 14字节,其实呢,在zval中数组,字符串和对象还需要另外的存储结构,数组则是一个 HashTable:

HashTable结构体定义在Zend/zend_hash.h.

[/crayon]
HashTable 结构需要 39 个字节,每个数组元素存储在 Bucket 结构中:

[/crayon]
Bucket 结构需要 33 个字节,键长超过四个字节的部分附加在 Bucket 后面,而元素值很可能是一个 zval 结构,另外每个数组会分配一个由 arBuckets 指向的 Bucket 指针数组, 虽然不能说每增加一个元素就需要一个指针,但是实际情况可能更糟。这么算来一个数组元素就会占用 54 个字节,与上面的估算几乎一样。

一个空数组至少会占用 14(zval) + 39(HashTable) + 33(arBuckets) = 86 个字节,作为一个变量应该在符号表中有个位置,也是一个数组元素,因此一个空数组变量需要 118 个字节来描述和存储。从空间的角度来看,小型数组平均代价较大,当然一个脚本中不会充斥数量很大的小型数组,可以以较小的空间代价来获取编程上的快捷。但如果将数组当作容器来使用就是另一番景象了,实际应用经常会遇到多维数组,而且元素居多。比如10k个元素的一维数组大概消耗540k内存,而10k x 10 的二维数组理论上只需要 6M 左右的空间,但是按照 memory_get_usage 的结果则两倍于此,[10k,5,2]的三维数组居然消耗了23M,小型数组果然是划不来的。

MySQL慢查询

原文

1 概念

MySQL的慢查询,全名是慢查询日志,是MySQL提供的一种日志记录,用来记录在MySQL中响应时间超过阀值的语句。

具体环境中,运行时间超过 long_query_time值的SQL语句,则会被记录到慢查询日志中。

long_query_time的默认值为 10,意思是记录运行 10秒以上的语句。

默认情况下,MySQL数据库并不启动慢查询日志,需要手动来设置这个参数。

当然,如果不是调优需要的话,一般不建议启动该参数,因为开启慢查询日志会或多或少带来一定的性能影响。

慢查询日志支持将日志记录写入文件和数据库表。

官方文档,关于慢查询的日志介绍如下(部分资料,具体参考官方相关链接):

2 参数

MySQL 慢查询的相关参数解释:

slow_query_log:是否开启慢查询日志, 1表示开启, 表示关闭

log-slow-queries :旧版(5.6以下版本)MySQL数据库慢查询日志存储路径。可以不设置该参数,系统则会默认给一个缺省的文件 host_name-slow.log

slow-query-log-file:新版(5.6及以上版本)MySQL数据库慢查询日志存储路径。可以不设置该参数,系统则会默认给一个缺省的文件 host_name-slow.log

long_query_time:慢查询阈值,当查询时间多于设定的阈值时,记录日志。

log_queries_not_using_indexes:未使用索引的查询也被记录到慢查询日志中(可选项)。

log_output:日志存储方式。 log_output='FILE'表示将日志存入文件,默认值是 'FILE'log_output='TABLE'表示将日志存入数据库。

3 配置

3.1 slow_query_log

默认情况下 slow_query_log的值为 OFF,表示慢查询日志是禁用的,可以通过设置 slow_query_log的值来开启,如下所示:

使用 set global slow_query_log=1开启了慢查询日志只对当前数据库生效,MySQL重启后则会失效。

如果要永久生效,就必须修改配置文件 my.cnf(其它系统变量也是如此)。

my.cnf要增加或修改参数 slow_query_logslow_query_log_file,如下所示

然后重启MySQL服务器。

3.2 slow_query_log_file

这个参数用于指定慢查询日志的存放路径,缺省情况是 host_name-slow.log文件,

3.3 long_query_time

开启了慢查询日志后,什么样的SQL才会记录到慢查询日志里面呢?

这个是由参数 long_query_time控制,默认情况下 long_query_time的值为10秒,可以使用命令修改,也可以在my.cnf参数里面修改。

关于运行时间正好等于 long_query_time的情况,并不会被记录下来。

也就是说,在mysql源码里是判断大于 long_query_time,而非大于等于。

从MySQL 5.1开始, long_query_time开始以微秒记录SQL语句运行时间,之前仅用秒为单位记录。

如果记录到表里面,只会记录整数部分,不会记录微秒部分。

如上所示,我修改了变量 long_query_time,但是查询变量 long_query_time的值还是 10,难道没有修改到呢?

注意:使用命令 set global long_query_time=4修改后,需要重新连接或新开一个会话才能看到修改值。

show variables like 'long_query_time'查看是当前会话的变量值。

也可以不用重新连接会话,而是用 show global variables like 'long_query_time';

3.4 log_output

log_output参数指定日志的存储方式。

log_output='FILE'表示将日志存入文件,默认值也是 'FILE'

log_output='TABLE'表示将日志存入数据库,这样日志信息就会被写入到 mysql.slow_log表中。

同时也支持两种日志存储方式,配置的时候以逗号隔开即可,如: log_output='FILE,TABLE'

日志记录到系统的专用日志表中,要比记录到文件耗费更多的系统资源。

因此对于需要启用慢查询日志,又需要能够获得更高的系统性能,那么建议优先记录到文件

3.5 log-queries-not-using-indexes

该系统变量指定未使用索引的查询也被记录到慢查询日志中(可选项)。

如果调优的话,建议开启这个选项。

另外,开启了这个参数,其实使用 full index scan的SQL也会被记录到慢查询日志。

3.6 log_slow_admin_statements

这个系统变量表示,是否将慢管理语句例如 ANALYZETABLETABLE等记入慢查询日志。

3.7 Slow_queries

如果你想查询有多少条慢查询记录,可以使用 Slow_queries系统变量。

另外,还有 log_slow_slave_statements --logshort-format 参数,可到MySQL网站了解。

4 mysqldumpslow工具

在生产环境中,如果要手工分析日志,查找、分析SQL,显然是个体力活。

MySQL提供了日志分析工具 mysqldumpslow

查看 mysqldumpslow的帮助信息:

 

比如,得到返回记录集最多的10个SQL。

得到访问次数最多的10个SQL

得到按照时间排序的前10条里面含有左连接的查询语句。

另外建议在使用这些命令时结合 |more 使用 ,否则有可能出现刷屏的情况。

 

人生的悲剧只有两种:一种是没有得到自己想要的东西,另一种是得到自己想要的东西。
                                —王尔德

标签

打赏