作者: xiaogang

  • docker 常用命令

    docker 常用命令

     

    docker 使用时 常用的命令

    了解指定的 Docker 命令使用方法
    docker command –help

    搜索镜像
    docker search ubuntu

    拉取镜像
    docker pull ubuntu:22.10

    推送镜像到Docker仓库
    docker push chunblog/ubuntu:20220809

    将容器保存为镜像
    docker commit -a “chunblog” -m “ubuntu:22.10 update” f8ccd6d9c225 ubuntu:20220809

    -a:指定镜像作者
    -m:描述信息
    f8ccd6d9c225:容器ID
    ubuntu:20220809:要创建的目标镜像名

    删除镜像
    docker rmi ubuntu:22.10

    运行容器
    docker run -it ubuntu:22.10 /bin/bash

    可用参数
    -d, –detach=false, 指定容器运行于前台还是后台,默认为false
    -i, –interactive=false, 打开STDIN,用于控制台交互
    -t, –tty=false, 分配tty设备,该可以支持终端登录,默认为false
    -u, –user=””, 指定容器的用户
    -a, –attach=[], 登录容器(必须是以docker run -d启动的容器)
    -w, –workdir=”” 指定容器的工作目录
    -c, –cpu-shares=0 设置容器CPU权重,在CPU共享场景使用
    -e, –env=[] 指定环境变量,容器中可以使用该环境变量
    -m, –memory=”” 指定容器的内存上限
    -P, –publish-all=false 指定容器暴露的端口
    -p, –publish=[] 指定容器暴露的端口
    -h, –hostname=”” 指定容器的主机名
    -v, –volume=[] 给容器挂载存储卷,挂载到容器的某个目录
    –volumes-from=[] 给容器挂载其他容器上的卷,挂载到容器的某个目录
    –cap-add=[] 添加权限,权限清单详见:http://linux.die.net/man/7/capabilities
    –cap-drop=[] 删除权限,权限清单详见:http://linux.die.net/man/7/capabilities
    –cidfile=”” 运行容器后,在指定文件中写入容器PID值,一种典型的监控系统用法
    –cpuset=”” 设置容器可以使用哪些CPU,此参数可以用来容器独占CPU
    –device=[] 添加主机设备给容器,相当于设备直通
    –dns=[] 指定容器的dns服务器
    –dns-search=[] 指定容器的dns搜索域名,写入到容器的/etc/resolv.conf文件
    –entrypoint=”” 覆盖image的入口点
    –env-file=[] 指定环境变量文件,文件格式为每行一个环境变量
    –expose=[] 指定容器暴露的端口,即修改镜像的暴露端口
    –link=[] 指定容器间的关联,使用其他容器的IP、env等信息
    –lxc-conf=[] 指定容器的配置文件,只有在指定–exec-driver=lxc时使用
    –name=”” 指定容器名字,后续可以通过名字进行容器管理,links特性需要使用名字
    –net=”bridge” 容器网络设置:
    bridge 使用docker daemon指定的网桥
    host 容器使用宿主机的网络
    container:NAME或ID 使用其他容器的网路,共享IP和PORT等网络资源
    none 容器使用自己的网络(类似–net=bridge) 但是不进行配置
    –privileged=false, 指定容器是否为特权容器,特权容器拥有所有的capabilities
    –restart=”no” 指定容器停止后的重启策略:
    no:容器退出时不重启
    on-failure:容器故障退出(返回值非零)时重启
    always:容器退出时总是重启
    –rm=false 指定容器停止后自动删除容器(不支持以docker run -d启动的容器)
    –sig-proxy=true 设置由代理接受并处理信号,但是SIGCHLD、SIGSTOP和SIGKILL不能被代理

    运行一个与宿主机公用网络的容器 就不需要映射端口了

    docker run –name chunblog –net=host –restart=always -dit -v /www/server/mysqlData:/www/server/mysqlData -v /www/backup:/www/backup -v /www/wwwlogs:/www/wwwlogs -v /www/wwwroot:/www/wwwroot chunblog/ubuntu:20220809

    不加–net=host时需要映射端口

    docker run –name chunblog –restart=always -dit -p 80:80 -p 443:443 -p 9706:9706 -p 888:888 -v /www/server/mysqlData:/www/server/mysqlData -v /www/backup:/www/backup -v /www/wwwlogs:/www/wwwlogs -v /www/wwwroot:/www/wwwroot chunblog/ubuntu:20220809

    查看运行中的容器
    docker ps

    查看所有容器
    docker ps -a

    启动容器
    docker start <容器ID>

    重启容器
    docker restart <容器ID>

    暂停容器
    docker pause <容器ID>

    取消暂停的容器
    docker unpause <容器ID>

    停止容器
    docker stop <容器ID>

    重启容器
    docker restart <容器ID>

    删除容器
    docker rm <容器ID>

    进入容器
    docker exec -it <容器ID> /bin/bash

    导出容器
    docker export <容器ID> > ubuntu.tar

    导入容器
    docker import ubuntu.tar chunblog/ubuntu:22.10

    查看容器运行日志
    docker logs <容器ID>

  • 使用 dockerfile 来构建自己的镜像

    使用 dockerfile 来构建自己的镜像

    Dockerfile 是一个文本文件,其内包含了一条条的 指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。

    Dockerfile 示例

    #基础镜像
    FROM ubuntu
    #添加文件到镜像
    COPY ./GatewayWorkerNew /www/server/GatewayWorker
    COPY start.sh /home/start.sh
    COPY php.ini /www/server/php/74/etc/php.ini
    #构架镜像时运行命理
    RUN chmod +x /home/start.sh && \
        rm -f /install.sh
    
    #为镜像添加匿名卷
    VOLUME ["/www/server/mysqlData","/www/backup","/www/wwwlogs","/www/wwwroot"]
    #暴露端口
    EXPOSE 80 443 9706 888
    #容器启动命令
    CMD ["sh","/home/start.sh"]

    FROM 指定基础镜像

    所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。

    这里我使用 ubuntu 作为基础镜像,你可以指定版本号比如 FROM ubuntu:20.04 不指定时默认使用 latest 版本,基础镜像是必须指定的。而 FROM 就是指定 基础镜像,因此一个 Dockerfile 中 FROM 是必备的指令,并且必须是第一条指令。

    COPY 的文件/目录复制到镜像内

    格式 COPY [–chown=<user>:<group>] <源路径>… <目标路径>

    拷贝文件到指定目录
    COPY start.sh /home/start.sh

    拷贝目录
    COPY ./GatewayWorkerNew /www/server/GatewayWorker

    在使用该指令的时候还可以加上 –chown=<user>:<group> 选项来改变文件的所属用户及所属组。
    COPY –chown=55:mygroup files* /mydir/
    COPY –chown=bin files* /mydir/
    COPY –chown=1 files* /mydir/
    COPY –chown=10:11 files* /mydir/

    RUN 在定制镜像时是执行的命令行

    在使用RUN命理时应该把命令整合为一条,Dockerfile 中每一个指令都会建立一层镜像,所以应该把命令使用 && 链接为一条命令。
    RUN chmod +x /home/start.sh && \
    rm -f /install.sh

    VOLUME 定义匿名卷

    容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中了,防止运行时用户忘记将动态文件所保存目录挂载为卷,在 Dockerfile 中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。

    VOLUME [“/www/server/mysqlData”,”/www/backup”,”/www/wwwlogs”,”/www/wwwroot”]

    VOLUME /www/server/mysqlData

    以上两种写法都是可以的

    EXPOSE 暴露端口

    格式为:EXPOSE <端口1> [<端口2>…]
    EXPOSE 指令是声明容器运行时提供服务的端口,这只是一个声明,在容器运行时并不会因为这个声明应用就会开启这个端口的服务。

    在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
    要将 EXPOSE 和在运行时使用 -p <宿主端口>:<容器端口> 区分开来。-p,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。

    CMD 容器启动命令

    Docker 不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。CMD 指令就是用于指定默认的容器主进程的启动命令的。
    提到 CMD 就不得不提容器中应用在前台执行和后台执行的问题。这是初学者常出现的一个混淆。
    Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样,用 systemd 去启动后台服务,容器内没有后台服务的概念。

    一些初学者将 CMD 写为:
    CMD service nginx start

    然后发现容器执行后就立即退出了。甚至在容器内去使用 systemctl 命令结果却发现根本执行不了。
    这就是因为没有搞明白前台、后台的概念,没有区分容器和虚拟机的差异,依旧在以传统虚拟机的角度去理解容器。

    对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它需要关心的东西。

    而使用 service nginx start 命令,则是希望 upstart 来以后台守护进程形式启动 nginx 服务。而刚才说了 CMD service nginx start 会被理解为 CMD [ “sh”, “-c”, “service nginx start”],因此主进程实际上是 sh。那么当 service nginx start 命令结束后,sh 也就结束了,sh 作为主进程退出了,自然就会令容器退出。

    正确的做法是直接执行 nginx 可执行文件,并且要求以前台形式运行。比如:
    CMD [“nginx”, “-g”, “daemon off;”]

    使用dockerfile文件构造镜像

    docker build –pull –rm -f dockerfile -t ubuntu:20220809

    build参数说明

    –build-arg=[] :设置镜像创建时的变量;

    –cpu-shares :设置 cpu 使用权重;

    –cpu-period :限制 CPU CFS周期;

    –cpu-quota :限制 CPU CFS配额;

    –cpuset-cpus :指定使用的CPU id;

    –cpuset-mems :指定使用的内存 id;

    –disable-content-trust :忽略校验,默认开启;

    -f :指定要使用的Dockerfile路径;

    –force-rm :设置镜像过程中删除中间容器;

    –isolation :使用容器隔离技术;

    –label=[] :设置镜像使用的元数据;

    -m :设置内存最大值;

    –memory-swap :设置Swap的最大值为内存+swap,”-1″表示不限swap;

    –no-cache :创建镜像的过程不使用缓存;

    –pull :尝试去更新镜像的新版本;

    –quiet, -q :安静模式,成功后只输出镜像 ID;

    –rm :设置镜像成功后删除中间容器;

    –shm-size :设置/dev/shm的大小,默认值是64M;

    –ulimit :Ulimit配置。

    –squash :将 Dockerfile 中所有的操作压缩为一层。

    –tag, -t: 镜像的名字及标签,通常 name:tag 或者 name 格式;可以在一次构建中为一个镜像设置多个标签。

    –network: 默认 default。在构建期间设置RUN指令的网络模式

    Dockerfile 指令表

    指令 使用方法 描述
    FROM FROM ubuntu 指定基础镜像
    RUN RUN apt update -y 构架镜像时执行的命令
    COPY COPY /dir /mydir/                     COPY –chown=www:nginx /dir /mydir/ 文件/目录复制到镜像内 可指定文件的所属用户及所属组
    ADD ADD mydata.tar.gz /data                COPY /dir /mydir/                     COPY –chown=www:nginx /dir /mydir/ ADD 指令和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能。如果 <源路径> 为一个 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,ADD 指令将会自动解压缩这个压缩文件到 <目标路径> 去。另外需要注意的是,ADD 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。因此在 COPY 和 ADD 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用 COPY 指令,仅在需要自动解压缩的场合使用 ADD。
    ENV ENV VERSION=1.0 DEBUG=on \
    NAME=”Happy Feet”
    ENV 设置环境变量
    ARG ARG DOCKER_USERNAME=ubuntu

    FROM ${DOCKER_USERNAME}/22.04            上面使用过以后就失效了,如果后面还需要使用需要再次指定

    ARG 构建参数 构建参数和 ENV 的效果一样,都是设置环境变量。所不同的是,ARG 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 ARG 保存密码之类的信息,因为 docker history 还是可以看到所有值的
    VOLUME VOLUME [“/data1″,”/data2”] 容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中,为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 Dockerfile 中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据
    EXPOSE EXPOSE 80 443 EXPOSE 指令是声明容器运行时提供服务的端口,这只是一个声明,在容器运行时并不会因为这个声明应用就会开启这个端口的服务。在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
    要将 EXPOSE 和在运行时使用 -p <宿主端口>:<容器端口> 区分开来。-p,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。
    WORKDIR WORKDIR /home 指定工作目录,以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。
    USER USER redis 指定当前用户,改变之后层的执行 RUN, CMD 以及 ENTRYPOINT 这类命令的身份。
    LABEL LABEL org.opencontainers.image.authors=”chunblog” LABEL 指令用来给镜像以键值对的形式添加一些元数据(metadata)
    SHELL SHELL [“/bin/sh”, “-c”] SHELL 指令可以指定 RUN ENTRYPOINT CMD 指令的 shell
    ONBUILD ONBUILD RUN [ “npm”, “install” ] ONBUILD 是一个特殊的指令,它后面跟的是其它指令,比如 RUN, COPY 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。
    HEALTHCHECK HEALTHCHECK [选项] CMD <命令> 健康检查
    ENTRYPOINT ENTRYPOINT [ “ping”, “114.114.114.114” ] ENTRYPOINT 入口点,ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数。ENTRYPOINT 在运行时也可以替代,不过比 CMD 要略显繁琐,需要通过 docker run 的参数 –entrypoint 来指定。
    CMD CMD [“bash”] 容器启动命令

     

  • 使用 acme.sh 部署 Let’s Encrypt 泛域名通用证书

    Let’s Encrypt两种域名验证方式

    1. DNS验证:配置一个随机的 TXT 记录来验证
    2. 文件验证:配置一个随机的 URL 地址来验证

    泛域名通用证书只能使用DNS TXT记录验证,acme.sh支持多种dnsapi我使用的是阿里云DNS,可以根据你的域名服务商进行选择支持列表。

    安装 acme.sh

    curl  https://get.acme.sh | sh -s email=my@example.com

    my@example.com 改为你自己的邮箱地址用于接收通知。

    acme.sh自动为你创建定时任务, 每天 0:00 点自动检测所有的证书, 如果快过期了, 需要更新, 则会自动更新证书。

    配置阿里云AK

    设置临时系统变量

    #你的阿里云AccessKeyId
    export Ali_Key="AccessKeyId"
    #你的AccessKeySecret
    export Ali_Secret="AccessKeySecret"

    颁发证书

    可以进行单域名、多域名、泛域名进行颁发。

    acme.sh --issue --dns dns_ali -d chunblog.com -d *.chunblog.com

    这里会使用dnsapi自动添加TXT记录,进行域名的 DNS 验证,中间会等待 2分钟左右来验证正确性,验证完成后记录会自动删除。

    出现Cert success表示成功 后面会有证书存放路径。

    复制/安装证书

    Nginx

    acme.sh --dns dns_ali -d chunblog.com -d *.chunblog.com\
     --install-cert\
     --key-file /www/cert/chunblog.com/key.pem\
     --fullchain-file /www/cert/chunblog.com/cert.pem\
     --reloadcmd "/etc/init.d/nginx reload"

    参数说明

    –install-cert    将颁发的证书安装到 apache/nginx 或任何其他服务器。

    –key-file    发行/续订后将密钥文件复制到的路径。

    –fullchain-file    发布/续订后将全链证书文件复制到的路径。

    –reloadcmd    发布/更新后重新加载服务器后要执行的命令

    然后修改Nginx配置文件使用 /www/cert/chunblog.com/key.pem、/www/cert/chunblog.com/cert.pem即可

    server
    {
        listen 80;
        listen 443 ssl http2;
        server_name chunblog.com www.chunblog.com;
        index index.php index.html index.htm;
        root /www/chunblog.com;
    
        ssl_certificate    /www/server/panel/vhost/cert/chunblog.com/fullchain.pem;
        ssl_certificate_key    /www/server/panel/vhost/cert/chunblog.com/privkey.pem;
        ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
        ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
        ssl_prefer_server_ciphers on;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;
    
        #禁止访问的文件或目录
        location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md)
        {
            return 404;
        }
        
        location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
        {
            expires      30d;
            error_log /dev/null;
            access_log /dev/null;
        }
        
        location ~ .*\.(js|css)?$
        {
            expires      12h;
            error_log /dev/null;
            access_log /dev/null; 
        }
        access_log  /www/wwwlogs/chunblog.com.log;
        error_log  /www/wwwlogs/chunblog.com.error.log;
    }

    安装acme.sh时已自动创建定时任务,证书到期前会自动更新证书并重载Nginx配置使证书生效。

  • Linux mysql数据库每天0点自动备份

    通过定时任务实现每天0点整备份数据,并保存最近30天的备份,过期自动删除。

    第一步新建 my_dump.cnf 配置文件

    my_dump.cnf配置文件用于储存数据库账号密码,在此以root为例,内容如下

    [mysqldump]
    #备份用户
    user=root
    #备份用户密码
    password=root

    第二部新建脚本文件

    内容如下:

    #!/bin/bash
    DB_NAME='demo1' #要备份的数据库
    BACKUP_DIR='/data/backup/mysqldata/' # 备份保存目录
    CURRENT_TIME=`date +%Y%m%d%H%M`
    FILEPATH=$BACKUP_DIR$DB_NAME'_'$CURRENT_TIME'.sql.gz'
    echo '开始导出数据库...'
    #defaults-extra-file=/root/my_dump.cnf 第一步的配置文件路径
    mysqldump --defaults-extra-file=/root/my_dump.cnf $DB_NAME | gzip > $FILEPATH
    #删除30天前的配置文件
    find ${BACKUP_DIR} -mtime +30 -name "${DB_NAME}_*.sql.gz" -exec rm -f {} \;
    echo '导出成功,文件名为: '$FILEPATH

    第三步添加定时任务

    执行命令:crontab -e

    写入以下内容:

    0 0 * * *       /data/crontab/database_backup.sh #每天0点0分备份数据库

    至此数据库自动备份已配置完成!

    注意事项

    确认cron任务是启动状态,以Centos7 为例 输入 systemctl status crond 显示绿色状态

    输入crontab -l  确认你输入的内容已保存

  • Linux crontab实现秒级定时任务

    Linux crontab 定时任务最少到每分钟执行一次,一些需要频繁运行启动的应用场景无法满足。

    Linux crontab:

    *    *    *    *    *
    -    -    -    -    -
    |    |    |    |    |
    |    |    |    |    +----- day of week (0 - 7) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
    |    |    |    +---------- month (1 - 12) OR jan,feb,mar,apr ...
    |    |    +--------------- day of month (1 - 31)
    |    +-------------------- hour (0 - 23)
    +------------------------- minute (0 - 59)

    crontab能到分钟级,我们可以在sh文件里写一个循环,然后每循环一次间隔多少秒执行下次循环。

    先不说了看代码

    #!/bin/sh
    step=2 #循环间隔的秒数
    #(i+step) 是每次循环i值+step 也就是每次循环+2 i到60停止循环
    for (( i = 0; i < 60; i=(i+step) )); do   
            /www/server/php/56/bin/php /www/wwwroot/crontab.php
    	/www/server/php/56/bin/php /www/wwwroot/crontab_1.php
    	/www/server/php/56/bin/php /www/wwwroot/crontab_2.php
    	/www/server/php/56/bin/php /www/wwwroot/crontab_3.php
    	/www/server/php/56/bin/php /www/wwwroot/crontab_4.php
    	/www/server/php/56/bin/php /www/wwwroot/crontab_5.php
    	/www/server/php/56/bin/php /www/wwwroot/crontab_6.php
    	/www/server/php/56/bin/php /www/wwwroot/crontab_7.php
        sleep $step
    done
    exit 0

    我在项目里使用这种方式定时任务稳定运行了有半年了,会有一点点的时间误差 因为中间PHP脚本运行需要耗时,但是这些误差可以忽略不计。

    crontab添加定时任务的时候需要根据脚本的几个数值做相应的时间调整

    比如我上面的间隔时间是2秒,每次循环i都会加2,当i到60的时候就会停止,crontab定时任务如下

    执行crontab -e 添加如下内容 每分钟运行一次

    */1 * * * * /data/apps/crontab/php_api_clear.sh

    比如你的任务需要5秒运行一次 间隔时间(step =5)循环 i 到180 停止 那么定时任务应设为每3分钟执行一次,

    脚本内容如下:

    #!/bin/sh
    step=5 #间隔的秒数
    for (( i = 0; i < 180; i=(i+step) )); do
            /www/server/php/56/bin/php /www/wwwroot/crontab.php
    	/www/server/php/56/bin/php /www/wwwroot/crontab_1.php
    	/www/server/php/56/bin/php /www/wwwroot/crontab_2.php
    	/www/server/php/56/bin/php /www/wwwroot/crontab_3.php
    	/www/server/php/56/bin/php /www/wwwroot/crontab_4.php
    	/www/server/php/56/bin/php /www/wwwroot/crontab_5.php
    	/www/server/php/56/bin/php /www/wwwroot/crontab_6.php
    	/www/server/php/56/bin/php /www/wwwroot/crontab_7.php
        sleep $step
    done
    exit 0

     

  • Mysql的联合索引

    Mysql联合索引又叫复合索引,就是一个覆盖表中两列或者以上的索引,例如WordPress的Posts表联合索引如下

    type_status_date(post_type, post_status, post_date, ID)

     

    创建联合索引

    1.执行alter table语句时创建

    alter table table_name add index index_name(column_list)

    index_name是创建的联合索引的名字,可以没有,没有的话系统会根据该索引包含的第一列来赋名称;table_name是要创建该索引的表名;column_list为该索引所包含的表的字段名。

     

    2.执行create index语句时创建

    create index index_name on table_name(column_list)
    此种情况是在表已经创建好的情况下,再来创建复合索引。index_name和column_list同上;table_name是要创建索引的表名。

    例子
    create table test
    (
    id int,
    name varchar(10),
    age int,
    primary key(id)
    );
    ALTER TABLE stu ADD INDEX NameAge (name,age);
    或使用
    create index NameAge on test(name,age);

    执行上面的语句后在表test中就创建好了一个名叫NameAge联合索引,在使用联合索引的时候,我们遵守一个最左原则,即索引 NameAge (name,age)支持name|name age组合查询,而不支持age查询;换句话说,在执行

    select * from test where name=?
    或使用

    select * from test where name=? and age=?
    时联合索引才会有效,如果执行

    select * from test where age=?
    则联合索引不会生效

     

    如果我们是在name和age上分别创建单个索引的话,由于mysql查询每次只能使用一个索引,所以虽然这样已经相对不做索引时全表扫描提高了很多效率,但是如果在name、age两列上创建复合索引的话将带来更高的效率。如果我们创建了(name, age)的复合索引,那么其实相当于创建了(name)、(name,age)两个索引,这被称为最佳左前缀特性。

    因此我们在创建复合索引时应该将最常用作限制条件的列放在最左边,依次递减。

    注意事项

    只要列中包含有NULL值都将不会被包含在索引中
    复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的,所以我们在数据库设计时尽可能不要让字段的默认值为NULL。

  • 群晖 Synology DSM Docker 设置国内镜像加速

    群晖自带Docker套件非常实用,我在使用时发现不管是群晖Docker内置套件下载镜像或者登录ssh docker pull都不成功,经过测试发现是 因为国内网络大环境的问题 docker hub pull镜像时网络不通,解决方式使用国内镜像加速,这里我推荐阿里的,免费的呦!

    使用SSH工具登录

    vi /var/packages/Docker/etc/dockerd.json
    
    #修改以下域名为你的地址
    {
       "data-root" : "/var/packages/Docker/target/docker",
       "log-driver" : "db",
       "ipv6": true,
       "registry-mirrors" : ["https://xxxx.mirror.aliyuncs.com"]
    }
    

    输入wq保存,然后重启群晖,再试试吧!