分类 PHP 下的文章

Rasmus Lerdorf 还做一个叫做 Form Interpreter 的项目,可以轻松地将SQL查询嵌入到网页中。它基本上是另一个CGI包装器,可以解析SQL查询,并能在这些查询的基础上轻松创建表单和表格,Rasmus Lerdorf 最终将两个项目合并到了一起,将其合并成为了一个程序,也就是 PHP/FI。现在它已经发展到了嵌入 HTML 文件的简单编程语言的程度,所以代码量飞起,直接涨了接近 20 多倍。

这个阶段的 PHP/FI 此时已经具备了 PHP 的雏形,PHP 完成从“个人主页工具”到 “个人主页建设工具包”。

2023-03-22T15:20:10.png

PHP脚本语言的语法在很多方面与C语言相似。它支持变量、数组、函数调用、不同的变量类型和大多数编写复杂的cgi程序时可能需要的东西。也就是说 PHP 编程语言正式出现了!

在PHP/FI 中引入了 yacc 和 lex 进行词法分析和语法解析,其原理其实还是通过解析 html 中的标记位,然后通过词法解析和语法解析成为C 语言代码进行执行,其核心代码在 lex.cparse.c 两个文件中。

我们先来看一下 PHP/FI 的使用,假设你有一个表单。

<FORM ACTION="/cgi-bin/php.cgi/~userid/display.html" METHOD=POST>。
<INPUT TYPE="text" name="name">
<INPUT TYPE="text" name="age"> <INPUT TYPE="text" name="age" >。
<INPUT TYPE="提交">
</FORM>

然后你的display.html文件可以包含这样的内容。

<?
    if($age>50);
        echo "Hi $name, you are ancient!<p>";
    elseif($age>30);
        echo "Hi $name, you are very old!<p>";
    else;
        echo "Hi $name.";
    endif;
>

就是这么简单! PHP/FI为表单中的每个输入字段自动创建一个变量。然后你可以在ACTION URL文件中使用这些变量。

上面的这段例子是来自于 PHP/FI 的文档,其文档地址在压缩包中也存在,目录是 doc。

2023-03-22T12:54:33.png

这个时候的 PHP/FI 还提供了 mysql 数据库:

2023-03-22T12:57:16.png

    <?
      $name = "bob";    
      $result = mysql($database,"select * from table where firstname='$name'");
      $num = mysql_numrows($result);
      echo "$num records found!<p>";
      $i=0;
      while($i<$num);
        echo mysql_result($result,$i,"lcase(fullname)");
        echo "<br>";
        echo mysql_result($result,$i,"address");
        echo "<br>";
        $i++;
      endwhile;
    >

其实到了这一步,我们的 PHP/FI 其实就已经可以完成目前我们的日常业务开发了,也就是 CURD。

同时我们可以通过 changelog 就可以看出,越来越多的人参与到了 PHP 的研发工作当中,也正是因此,PHP 逐渐壮大到了今天这个地步。

2023-03-13T18:17:10.png

目前 PHP/FI 的文档还可以访问 https://www.php.net/manual/phpfi2.php ,有兴趣的朋友可以去看一下。

源码解析

PHP 的本质其实还是 C,这也是大多数脚本语言的本质,我们可以把脚本语言的解释器理解为就是一个特殊的程序,解释器的将其中的各种语法解析、转换成可以执行的 C 代码而已。如果这么理解,那么对于脚本语言的理解就很容易了。

那么我们在定义一个变量,自定义一个函数的时候,其实解释器需要将这些变量、函数存储起来,然后在需要使用的地方进行调用。

接下来,我们就来看一下,PHP/FI中的自定义函数、变量是如何存储的。

PHP 的函数保存在哪里?

内置函数

在了解自定义函数的存储之前,我们先来看一下内置函数是如何进行处理的,在 PHP/FI 中为我们提供了大量的内置函数。

所有的内置函数都会被存储在一个变量名叫做 cmd_table 的 hashtable 中。

typedef struct _cmd_table_t {
    char *cmd;
    unsigned int token;
    void (*fnc)(void);
} cmd_table_t;

  • cmd 是函数的名称
  • token 是token 的编号
  • 最后一个成员是指向函数的指针

2023-03-22T15:29:12.png

自定义函数

2023-03-22T15:24:40.png

PHP 中的变量

支持的变量类型

支持三种类型的变量。长整数、双精度浮点和字符串。

#define    DNUMBER    258
#define    LNUMBER    259
#define    STRING    260

PHP 通过类型推断来判断变量具体的数据类型。

/*
 * Determines if 'str' is an integer, real number or a string
 *
 * Note that leading zeroes automatically force a STRING type
 */
int CheckType(char *str) {
    char *s;
    int type=LNUMBER;

    s = str;
    if(*s=='0' && *(s+1) && *(s+1)!='.') return(STRING);
    if(*s=='+' || *s=='-' || (*s>='0' && *s <='9') || *s=='.' ) {
        if(*s=='.') type=DNUMBER;
        s++;
        while(*s) {
            if(*s>='0' && *s<='9') { 
                s++; 
                continue; 
            }
            else if(*s=='.' && type==LNUMBER) { type=DNUMBER; s++; continue; }
            else return(STRING);
        }
    } else return(STRING);
    return(type);
} /* CheckType */

表达式的栈管理

/* Expression Stack */
typedef struct Stack {
    short type;
    char *strval;
    long intval;
    double douval;
    VarTree *var;    
    struct Stack *next;
    int flag;
} Stack;

变量的存储

变量的存储,在这个版本中的 PHP 存储变量使用的并不是 HashTable,而是使用的树。这说明 PHP 的设计也是在不断优化调整的过程。


/* Variable Tree */
typedef struct VarTree {
    short type;
    int count;
    char *name;
    char *strval;
    char *iname;
    long intval;
    double douval;
    int flag;
    int scope;                /* 0=local to frame, 4=global, 8=static to frame */
    struct VarTree *left;
    struct VarTree *right;
    struct VarTree *next;
    struct VarTree *prev;
    struct VarTree *lacc;
    struct VarTree *lastnode;
    int deleted;
    int allocated;
} VarTree;

这个时候的变量的值全部都是存在 tree 中的,根据 type 来判断变量的类型。

socpe 实现了变量的作用域。

参考

Personal Home Page Tools

1.0.8 是我们在官网上能够下载到的最古老的版本,虽然这个时候也叫 PHP,但是和现在的 PHP 意思是完全不同的,下面这张图是在源代码中的截图。

2023-03-13T08:49:59.png

PHP Tools - Personal Home Page Tools 个人网站工具集,严格意义上来说,这个时候的 PHP 只是一个 CGI 的工具集,它包含了一个非常简单的语法分析引擎,只能理解一些指定的宏和一些Home Page后台的常见功能,如留言本,计数器和一些其他的素材。

2023-03-22T13:01:01.png

Rasmus Lerdorf,就是这个家伙,在 1995 年仅用了一个下午就完成了 PHP 的第一个版本,对我们的生活其实产生了深远的影响。在 2004 年 PHP 更是成为了年度语言,并且在其后很长的一段时间内保持着前五,虽然近些年来 PHP 一直在被唱衰,甚至在国内大厂不断地用 Go 代替 PHP 的环境下,在 2023 年仍然没有跌出前十。

PHP 源代码下载,历史的归档源代码我们可以到 https://museum.php.net/ 这里进行下载。

2023-03-13T11:15:18.png

我们用 cloc 分析一下源代码发现,这个时候的 'PHP' 其实只有两千多行代码,其中真正用 C 语言实现的代码共计是 2455 行,等到了php2.0.1 的时候, C 语言的代码量就已经打到了进阶 58957 行。

2023-03-13T11:13:10.png

和现在的 PHP 代码行数完全不是一个量级的,这是因为在当年大多数都是静态页面,而开发 PHP 的目的就是为了统计网站的访问人数。

这个时候的 PHP 是如何执行的呢,又或者 CGI 程序是怎么回事?

用 Shell 也能写网站

这里不会跟朋友们扯太多空洞洞的理论,因为理论知识很容易就可以获取到,随便看几本书就可以了,或者去百度百科,都会有非常详细的介绍。

在上世纪 90 年代互联网刚刚起步,那个时候大家都是在用 html 搭建一个个人简历或者是公司简介,这个时代就是 web1.0 时代,很快 CGI 出现了,拜 CGI 之赐,网站不再只有固定不变的图形和文字,借由程序动态产生的网页可以让网站好象『活』了起来。小从简单的网页计数器,留言版,大至处理众多资料的搜寻引擎,可做线上实时交易的电子商务、网络下单等。CGI 简单、开放、跨平台、与程序语言独立的特性,使得编写网站应用程序变得很容易。

  1. 用户访问apache
  2. apache 调用 cgi程序,在这个过程中会将请求数据发送给 cgi 程序。
  3. cgi 输出执行业务逻辑并且输出页面。

按照这个原理,其实任何语言都可以编写 cgi 程序,下面我们用 shell 来编写一个打印 get 参数的 echo 服务。

#!/bin/bash

echo 'Status: 200 OK'
echo 'Content-Type: text/html; charset=utf-8'
echo 'Cache-Control: no-cache'
echo 'Pragma: no-cache'
echo
echo '<html>'
echo '<head>'
echo '<h1>echo query:</h1>'
echo '<p>'
echo  $QUERY_STRING
echo '</p>'
echo '</body>'
echo '</html>'
echo

2023-03-13T11:37:26.png

PHP 的使用案例

这个时候 PHP 提供了四个 cgi 程序:phpl.cgi, phpf.cgi, phplmon.cgi, phplview.cgi

其实这个时候的 PHP 就已经在简化 HTML 开发了,其中提供了一些内置函数可以帮我们进行模板替换。

<ul>
  <li>$today = <!--$today--></li>
  <li>$version = <!--$version--></li>
  <li>$_GET['name'] = <!--$name--></li>
  <li>system load:<pre><!--! w|head -n1 --></pre></li>
</ul>

<br>This page has been accessed a total of <a href="phplmon.cgi"><b>3</b></a> times now! <b>3</b> times today.<br>Page was last updated on Dec 22, 2021 at 7:43.</center></font>

2023-03-22T13:44:38.png

我们可以看到 <!--$today--> <!--$version--> 都已经被 phpl.cgi 程序给替换掉了。

PHP 源代码分析

PHP 的目录结构

这就是这个版本的 PHP 主要执行流程。我们来看一下代码目录

.
├── License
├── README
├── build
│   ├── phpf.cgi
│   ├── phpl.cgi
│   ├── phplmon.cgi
│   └── phplview.cgi
├── common.c
├── common.h
├── config.h
├── error.c
├── html_common.h
├── phpf.c
├── phpl.c
├── phplmon.c
├── phplview.c
├── post.c
├── post.h
├── subvar.c
├── version.h
├── wm.c
└── wm.h
  • common.c & common.h 一些公共函数的声明,我们看到有很多函数其实是没有.h 声明的,其实就放在了这里。
  • config.h : 相当于php.ini 用来存储 PHP 相关的配置信息
  • html_common.h && error.c :公共函数,这个名字起的让人很迷惑,里面有处理html_error 的处理函数,也有公用头部函数。
  • phpl.c
  • phplmon.c
  • phpview.c
  • phpf.c
  • subvar.c :变量替换函数
  • version.h :存放了 PHP 的版本信息,作者名字。
  • vm.c & vmc.h :字符串匹配函数,有趣的是这段代码并不是 Rasmus Lerdorf 写的,而是 COPY 过来的,并且他在代码中感谢了 Justin Slootsky。这说明无论是什么人都会有自己的短板。

在这里的 build 文件其实是不存在的,这是为了方便编译我自己就修改了 Makefile 文件。

PHPL.C 的执行流程

  1. 初始化变量
  2. 获取 Post 数据,如果有则初始化 Post 链表,如果没有则不执行
  3. 校验参数,也就是 CGI 程序发过来的 argv,校验不通过则渲染错误 html
  4. 渲染(其实就是标准输出)HTML,其中包括模板解析,替换等操作
  5. 释放Post 链表,结束程序

PHP 的配置文件

我们先来看配置文件 config.h :

define ROOTDIR "/usr/somewhere/user_id/public_html"
define HTML_DIR "html" 

#define LOGDIR "logs/"

#define ACCDIR "logs/"
#define NOACCESS "NoAccess.html"

这个时候的配置文件可以说是相当简洁了,只有四个参数,所以根本不需要独立的配置文件,我们只需要在编译之前进行修改就可以了。

  • ROOTDIR:项目根目录,在例子中,我们使用 phpl.cgi?var.html, var 就存储在根目录下,如果没有设置的话,回去找 apached 的默认配置,并且增加上 /public_html。
  • HTMLDIR:如果你不想选择使用 rootdir 也可以利用这个进行指定目录
  • LOGDIR:日志
  • ACCDIR:日志
  • NOACCESS:无法访问调转到指定页面。

PHP 的模板替换

在 phpl.c 中定义了两个宏。

#ifndef STARTSEP
#define STARTSEP "<!--"
#endif
#ifndef ENDSEP
#define ENDSEP   "-->"

这两宏的作用其实就是代表着模板替换的开始和结尾。

在这个时候,其实 PHP 有点类似于 Smarty 模板引擎,在 PHP 中预设了很多变量,当加载 HTML 的时候,如果发现 <!-- --> 模板标记,就会将其中的内容替换成已经赋值的变量

2023-03-22T13:47:28.png

我们可以看到截图中代码替换,其实就是检测到 $total 就替换成已经实现准备好的变量。

  • 在 632 和 637 行 其实就是去截取 <!-- --> 中的内容
  • 查找到对应的标记进行替换。

在 651 行中有 $today,我们以此举例。

static int todays_cnt;

在 phpl.c的最上方定义了静态变量 todays_cnt,其实该记录存储的就是今日的访问记录。

if(fgets(cntbuf,127,fp)) {
    s=strchr(cntbuf,' ');
    if(s) *s='\0';
        cnt=atoi(cntbuf);
        if(s) todays_cnt=atoi(s+1);
    } else {
    cnt=0;
    todays_cnt=0;
}

PHP 中的 Post 数据

用链表存储 Post 数据

2023-03-22T15:43:09.png

在 phpl.c 中第 88 行定义了一个全局静态变量, pdtop 其结构定义在 post.h 中。

typedef struct _postdata {
    char    var[32];
    char    val[128];
    struct _postdata *next;
} postdata;

这是一个链表,第一个 char 存储的事 post 的 key,第二个 char 存储的是值,在这里我们可以看出,在这个时候 PHP 最大只能接受 128 个字符。

获取 post 数据

在 cgi 协议中 http 请求中的数据是通过环境变量交给 cgi 程序的。

2023-03-22T15:37:12.png

Post 数据的释放

在我们申请内存后,必须对其进行释放,否则就会造成内存泄露,当 php 执行完成后会对已经申请过的内存地址进行释放。

2023-03-22T15:46:01.png

其实操作非常简单,就是判断第一个节点是否为空,如果不为空则证明有 post 的数据,然后开始遍历链表,释放掉所有申请的内存地址。

参考

目前企业大多数都是使用微服务架构作为解决方案,在这里我们使用 yaf + yar 来作为基础实现一套企业级的微服务解决方案。

Yaf 是鸟哥开发的基于 C 语言扩展的高性能框架,而 yar 是一款 rpc 解决方案。

安装 yaf

最简单的安装方式:

# 利用 pecl 安装 yaf
➜  ~ sudo pecl install yaf
# 验证是否安装成功
➜  ~ php -m | grep yaf
yaf

yaf 的 hello world

在正式开始之前,我们先来解决的代码提示,这是因为 yaf 作为 C 语言编写的扩展,我们的 phpstrom 无法给出代码提醒,这就降低了我们的研发效率,所以我们要先解决代码提示的问题。

➜  ~ git clone https://github.com/elad-yosifon/php-yaf-doc.git

然后打开 phpstrom,选择外部库,然后添加刚才下载的 php-yaf-doc**

2023-03-04T21:05:48.png

2023-03-04T21:06:03.png

这个时候我们再编写代码的时候就可以用到代码提醒了,这个时候我们按照国际惯例,开始编写 hello world程序。

我们先来建立标准目录,鸟哥在文档中给了我们很好的案例。

- .htaccess // Rewrite rules
+ public
  | - index.php // Application entry
  | + css
  | + js
  | + img
+ conf
  | - application.ini // Configure 
- application/
  - Bootstrap.php   // Bootstrap
  + controllers
     - Index.php // Default controller
  + views    
     |+ index   
        - index.phtml // View template for default controller
  + library // libraries
  + models  // Models
  + plugins // Plugins

2023-03-04T21:06:23.png

首先我们来看 public 下的 index。public 是公共目录,其中 index.php就是我们的入口文件。

define('APPLICATION_PATH', dirname(__FILE__, 2));
try {
    $app = new Yaf_Application(APPLICATION_PATH . "/conf/application.ini");
    $app->bootstrap() //call bootstrap methods defined in Bootstrap.php
    ->run();
} catch (Yaf_Exception_StartupError|Yaf_Exception_TypeError $e) {

}

首先是定义了应用目录,然后初始化 Yaf_Application,这里的异常我们先不处理。

这里,我们需要先创建 application.ini 这 Bootstrap.php。

[product]
;CONSTANTS is supported
application.directory = APPLICATION_PATH "/application/"
<?php
class Bootstrap extends Yaf_Bootstrap_Abstract
{
}

之后就是 IndexController了。

<?php

class IndexController extends Yaf_Controller_Abstract
{
    public function indexAction()
    {
        $this->getView()->assign('context', 'hello world');
    }
}

与其他框架一样,Yaf 也是一款 MVC 框架,我们可以直接利用 assign 像页面复制。

2023-03-04T21:06:40.png

这里我们需要注意目录结构,index 代表的是 IndexController,index.phtml才是 indexAction。我们通过PHP 内置的服务器来运行我们的应用。

➜  yaf-micro php -S localhost:8080 -t public

2023-03-04T21:07:00.png

yaf 的配置

yaf 框架的配置主要分为运行时配置和应用配置。

运行时配置

运行时配置是配置在 php.ini配置文件中的。

配置名称默认值含义
yaf.library全局路径,Yaf_loader会从这个目录检索全局库
yaf.action_prefer0如果路径信息中只有一部分,当设置为0时,会把这部分作为controller,如果设置为1,会把这部分作为action
yaf.lowcase_path0在类自动加载过程中是否将所有的路径转换为小写
yaf.use_spl_autoload0当设置为0时,Yaf_Loader::autoload()将一直返回true,设置为1时,如果Yaf_Loader找不到类时,将返回false,由其他自动加载方法处理
yaf.forward_limit5Yaf_Controller_Abstract::forward()的最大次数,防止递归次数过多,设置最大保护机制
yaf.name_suffix1当设置为1时,Yaf_Loader将根据类后缀名判断是否是一个MVC类,若设置为0,将根据类前缀名判断
yaf.name_separator当该值不为空时,Yaf_Loader将根据这个值来鉴定类后缀和值,如:当值为"_"时,Yaf_Loader将把Index_Controller作为控制器类,IndexController作为普通类
yaf.cache_config0当设置为1时,同时使用ini配置文件作为Yaf_Application()的参数时,ini配置文件的编译结果将被缓存到php进程中,Yaf根据ini文件的mtime判断配置是否更新,如果更新,Yaf将重新加载ini配置,注意,yaf使用ini文件路径作为缓存key,所以在ini文件路径中使用绝对路径,否则,如果两个应用程序使用相同的ini配置相对路径,可能会出现一些冲突。
yaf.environproduct用于yaf获取ini配置文件的config部分,如果该值为“product”,那么yaf将使用ini配置文件(Yaf_Application第一个参数)中名为“product”的部分作为Yaf_Application的最终配置。
yaf.use_namespace0当设置为1时,Yaf所有的类都将以命名空间的方式使用

预定义常量

常量名称含义
YAF_VERSIONyaf框架版本
YAF_ENVIRONyaf框架环境
YAF_ERR_STARTUP_FAILED错误码
YAF_ERR_ROUTE_FAILED错误码
YAF_ERR_DISPATCH_FAILED错误码
YAF_ERR_AUTOLOAD_FAILED错误码
YAF_ERR_NOTFOUND_MODULE错误码
YAF_ERR_NOTFOUND_CONTROLLER错误码
YAF_ERR_NOTFOUND_ACTION错误码
YAF_ERR_NOTFOUND_VIEW错误码
YAF_ERR_CALL_FAILED错误码
YAF_ERR_TYPE_ERROR错误码
  • get_defined_constants()方法获取yaf预定义的常量

应用配置

应用配置是在工程目录conf 目录下的 application.ini 中进行配置。

配置名称默认值含义
application.directory应用程序的目录,包含"controllers", "views", "models", "plugins"等子目录
application.extphpPHP脚本的扩展名,Yaf_Loader自动加载类的时候需要用到它
application.view.extphtml视图模板扩展名
application.modulesindex注册的模块列表,以逗号分隔,用于路由处理,特别是当PATH_INFO超过三段的时候
application.libraryapplication.directory . "/library"本地类库的目录
application.library.directoryapplication.directory . "/library"本地类库的目录,application.library的别名
application.library.namespace""逗号分隔的本地类库命名空间前缀,Yaf2.1.6以后加入
application.bootstrapapplication.directory . "/Bootstrap" . application.extBootstrap类脚本文件的绝对路径
application.baseUri""路由处理中需要忽略的路径前缀。举个例子,请求"/prefix/controller/action"时。如果你将application.baseUri设置为"/prefix",那么只有"/controller/action"会被当做路由路径。通常不需要设置此值。
application.dispatcher.defaultRoute默认路由,如果未指定,静态路由会被当做是默认路由
application.dispatcher.throwException1开启此项,Yaf会在发生错误的地方抛出异常。
application.dispatcher.catchException0开启此项,如果有未捕获的异常,Yaf将会把它定向到Error controller, Error Action。
application.dispatcher.defaultModuleindex开启此项,如果有未捕获的异常,Yaf将会把它定向到Error controller, Error Action。
application.dispatcher.defaultControllerindex开启此项,如果有未捕获的异常,Yaf将会把它定向到Error controller, Error Action。
application.dispatcher.defaultActionindex开启此项,如果有未捕获的异常,Yaf将会把它定向到Error controller, Error Action。
application.system在application.ini中设置Yaf运行时配置

大家好,我是一笑。

这个系列的博文是我曾经在慕课网学习时候的笔记内容,一转眼已经工作多年了,前段时间迁移博客,顺便把自己以前写的博文都看了一遍,感觉这个系列的内容其实还是可以重新编辑的,也算是对以前工作的一个总结。

当时只是作为笔记,并没有太多的实际操作部分,打算在这一次重写的时候把这一部分给补上。

目录

0x00 起步 https://www.maksim.website/archives/38/ 这篇文章主要用来讲解什么是并发等概念内容
0x00 Web 防盗链 https://www.maksim.website/archives/39/

在本文中,并没有实现过程,算是一个提纲,当我们需要对MySQL进行优化的时候,可以通过本篇文章,了解一下,我们要对MySQL进行哪些优化,也算是对MySQL的优化先要有一个总体的认知。

因为如果要将所有的操作过程都放到这篇文章中,估计还没等看完,你就已经睡着了,具体的操作,我会在其他系列的博文中陆续的更新出来。

优化方向

  • 数据表数据类型优化
  • 索引优化
  • SQL 语句优化
  • 存储引擎的优化
  • 数据表结构设计的优化
  • 数据库服务器架构的优化

数据表数据类型优化

在做数据表结构类型优化时,我们需要考虑如下几点:

  • 字段使用什么样的数据类型更合适
  • 字段使用什么样的数据类型性能更快

Int: tinyint、smallint、bigint

在使用Int类型存储值的时候,一定要按需选择,需要对空间、范围进行考虑,比如存储年龄通常是0~120多,所以我们选择一个最小的tinyint类型,如果加上无符号那么最大值是255,足够我们存储年龄,选择smallint或者bigint明显是一种浪费。

char、varchar

char 的空间效率要比 varchar 要好,如果是存储电话号码,固定为11位,这种类似的需求,使用char要更好。

对于varchar存储一些可变的数据,如用户名。

 enum

特性、固定的分类可以使用 enum 存储,效率更快。

一定要是固定的分类,如果将来的分类会变,就不适合使用enum,因为这样我们就需要去修改数据库表结构,扩展性会变得很差。

IP 地址的存储

IP 地址一般会采用字符型来进行存储,但是这种存储方式会带来很大的空间占用,我们可以使用整型来进行存储,PHP为我们提供了转换函数 ip2lang

索引优化

在做索引型优化时,我们需要考虑如下几点:

  • 建立合适的索引
  • 索引在什么场景下效率最高

索引的创建原则

  • 索引不是越多越好,在合适的字段上创建合适的索引,索引本身会影响我们的写操作的速度,并且会占用磁盘空间。
  • 符合索引的前缀原则。

索引的注意事项

  • 符合索引的前缀原则
  • like 查询%的问题
  • 全表扫描优化
  • or 条件索引使用情况
  • 字符串类型索引失效的问题

SQL 语句的优化

  • 优化查询过程中的数据访问

    • 使用Limit
    • 返回列不用 *
  • 优化长难句的查询语句

    • 变复杂为简单
    • 切分查询
    • 分解关联查询
  • 优化特定类型的查询语句

    • 优化count()
    • 优化关联查询
    • 优化子查询
    • 优化 Group by 和 distinct
    • 优化 limit 和 union

存储引擎的优化

  • 尽量使用 InnoDB 存储引擎

数据表结构设计的优化

  • 分区操作

    • 通过特定的策略对数据表进行物理拆分
    • 对用户透明
    • partition by
  • 分库分表

    • 水平拆分
    • 垂直拆分

数据库架构的优化

  • 主从复制
  • 读写分离
  • 双主热备
  • 负载均衡

    • 通过 LVS 的三种基本模式实现负载均衡
    • MyCat 数据库中间件实现负载均衡。