分类 技术 下的文章

在数据库性能优化的领域中,有一句流传甚广的话:“如果数据库优化是一栋大厦,那么索引就是地基。” 一个慢查询可能让网页加载延迟几秒,而在高并发场景下,这“几秒”就足以引发系统雪崩。MySQL索引作为加速查询的核心工具,用得好是利器,用不好反而成为负担。本文将深入浅出地介绍MySQL索引的核心原理,并为你总结一套拿来即用的索引优化规则。

一、索引的核心回顾:为什么它能这么快?
在讨论规则之前,我们必须先理解索引的底层逻辑。MySQL默认使用 B+树 作为索引的数据结构。

B+树的特性:数据仅存储在叶子节点,且叶子节点之间通过指针形成有序链表。这使得它不仅支持快速的等值查询,也非常适合范围查询(如 > 、 < 、 BETWEEN )和排序 。

聚簇索引 vs 辅助索引:

聚簇索引(主键索引) :叶子节点存储了整行数据。一张表只有一个。

辅助索引(二级索引) :叶子节点存储的是主键值。这意味着通过辅助索引查找数据时,通常需要先找到主键,再回到聚簇索引中查找完整数据,这个过程称为回表 。

理解了这两个基本概念,我们就能更好地把握下面这些优化规则。

二、索引设计的黄金法则

  1. 最左前缀原则
    这是联合索引中最重要、也最容易犯错的原则。MySQL创建联合索引 (a, b, c) 时,实际上是按 a、b、c 的顺序建立了一棵B+树。

生效规则:查询条件必须从索引的最左侧列开始,且不能跳过中间的列。

支持以下查询:

WHERE a=1

WHERE a=1 AND b=2

WHERE a=1 AND b=2 AND c=3

WHERE a=1 AND c=3 ——(注意:仅 a 列能用到索引,c 列用不到,但索引会用来过滤 a)

不支持/部分支持:

WHERE b=2 ——(索引失效)

WHERE c=3 ——(索引失效)

WHERE a=1 AND c=3 ——(a 生效,c 不生效)

技巧:在创建联合索引时,将最常用于查询条件的列放在最左边。

  1. 高选择性优先
    索引的选择性 = 列中不同值的数量 / 总行数。选择性越接近1,索引价值越大。

反例:对性别字段(仅有男/女)建立索引。由于需要回表扫描大量数据,优化器可能认为还不如全表扫描快,导致索引失效 。

正解:将低选择性的列与高选择性的列组成联合索引。例如 INDEX(city, gender),先通过城市过滤掉大部分数据 。

  1. 覆盖索引
    如果一个索引包含(或覆盖)了所有需要查询的字段,那就不需要回表了。这是减少磁盘I/O的杀手锏。

优化前:SELECT name, age FROM users WHERE age=20; (假设仅有 age 索引,查到主键后需要回表获取 name 和 age)

优化后:创建索引 INDEX age_name(age, name)。
此时查询分析器显示 Extra: Using index,表示使用了覆盖索引,性能提升可达数倍 。

三、索引失效的常见场景(避坑指南)
建立了索引并不代表一定会被使用。以下场景会导致索引失效,让查询退化为全表扫描:

  1. 对索引列进行了计算或函数操作
    错误:WHERE YEAR(create_time) = 2025

正确:WHERE create_time >= '2025-01-01' AND create_time < '2026-01-01'

  1. 隐式类型转换
    场景:phone 字段类型为 varchar,查询时 WHERE phone = 13800001111(用数字比较)。

结果:MySQL会将字符串转为数字,相当于在索引列上用了函数,导致索引失效 。

  1. 使用 != 或 <> 或 IS NOT NULL
    对于非主键索引,不等于操作通常无法利用索引进行高效查找。如果NULL值过多,IS NULL 也可能失效 。
  2. 左模糊查询
    LIKE '%关键字' 无法使用索引,而 LIKE '关键字%' 则可以 。
  3. OR条件
    如果 OR 连接的两个条件中,有一个字段没有索引,那么整个查询将无法使用索引(除非使用 UNION 替代) 。

四、实战优化策略

  1. 索引下推
    这是MySQL 5.6引入的优化。

无ICP(索引下推) :根据索引定位到数据行,回表,再过滤其他条件。

有ICP:在存储引擎层遍历索引时,直接对索引中包含的字段进行过滤,减少回表次数。

示例:索引 (city, age),查询 WHERE city=xxx AND age=30。ICP允许在索引内部就判断 age=30,无需将所有满足 city 条件的记录都回表 。

  1. 联合索引顺序设计
    通用公式:等值查询列 → 范围查询列 → 排序/分组列。

案例:查询 WHERE city=北京 AND age>20 ORDER BY create_time。

索引建议:(city, create_time)。因为 age 是范围查询,放在后面可能会导致 create_time 无法用于排序 。

  1. 控制索引数量
    索引不是越多越好!每张表建议控制在5个以内。

代价:每个索引都会占用磁盘空间,且每次 INSERT、UPDATE、DELETE 操作都需要同步维护所有索引,写性能会下降30%甚至更多 。

  1. 利用 EXPLAIN 分析
    写完SQL后养成好习惯,用 EXPLAIN 看一下执行计划,重点关注:

type:至少达到 range 或 ref,尽量避免 ALL(全表扫描)。

key:实际使用的索引是哪个。

Extra:出现 Using filesort(文件排序)或 Using temporary(临时表)通常意味着需要优化 。

五、总结
MySQL索引优化并非一朝一夕之功,它是一门关于权衡的艺术。我们通过B+树原理理解其运作方式,通过最左前缀原则设计联合索引,通过覆盖索引减少回表,同时时刻警惕那些导致索引失效的操作。

最后送你一条优化的“心法口诀”:
“全值匹配我最爱,最左前缀要遵守;
带头大哥不能死,中间兄弟不能断;
索引列上少计算,范围之后全失效;
LIKE百分写最右,覆盖索引不回表。”

针对 v15.3.3-jh 版本安装并配置 GitLab Runner 以实现代码同步,我将为你提供详细的步骤。该方案的核心是:在15.3.3版本上安装兼容的Runner,并通过CI/CD流水线实现代码自动同步到服务器。

第一步:安装 GitLab Runner (v15.3.3 兼容版本)
对于 GitLab 15.3.3,建议安装与之兼容的 Runner 版本(如 v15.x 系列)。

添加官方仓库并安装:

bash
# 对于 Linux x86-64 系统
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash

# 安装特定版本(例如 15.11.0,这是与 15.3 兼容的较新Runner)
sudo apt-get install gitlab-runner=15.11.0

# 对于 CentOS/RHEL
# curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh" | sudo bash
# sudo yum install gitlab-runner-15.11.0
验证安装:

bash
gitlab-runner --version
# 应显示类似:Version:      15.11.0
第二步:注册 Runner 到 GitLab 项目
注册Runner前,需要从GitLab项目获取令牌。

获取注册令牌:

进入项目页面:项目设置 → CI/CD → Runner

在 “设置Runner” 部分找到 “注册令牌”

或者在群组/实例级别获取令牌(范围更广)

执行注册命令:

bash
sudo gitlab-runner register
输入GitLab实例URL:http://你的GitLab服务器地址 或 https://...

输入获取的注册令牌

描述Runner:例如 code-sync-runner

添加标签(重要):输入 code-sync(后续CI脚本会用到)

选择执行器:推荐 shell(简单)或 docker(隔离性好)。这里以 shell 为例。

第三步:配置 Runner 以访问目标服务器
为了实现代码同步,Runner需要能免密登录到你的部署服务器。

在Runner主机生成SSH密钥:

bash
sudo -u gitlab-runner ssh-keygen -t ed25519
# 一直按回车,使用默认路径
将公钥部署到目标服务器:

bash
# 查看公钥
sudo cat /home/gitlab-runner/.ssh/id_ed25519.pub

# 将输出的内容,添加到目标服务器的 ~/.ssh/authorized_keys 文件中
测试SSH连接:

bash
sudo -u gitlab-runner ssh 目标服务器用户名@目标服务器IP "echo 连接成功"
第四步:创建 CI/CD 流水线实现自动同步
在你的GitLab仓库根目录创建 .gitlab-ci.yml 文件。

yaml
stages:
  - sync

# 定义同步到服务器的任务
sync_to_server:
  stage: sync
  tags:
    - code-sync  # 必须与注册Runner时填的标签一致
  only:
    - main  # 只在main分支推送时触发,可根据需要改为其他分支
  script:
    - echo "开始同步代码到服务器..."
    - |
      rsync -avz --delete --exclude='.git' --exclude='.gitlab-ci.yml' \
        -e "ssh -o StrictHostKeyChecking=no" \
        $CI_PROJECT_DIR/ 目标服务器用户名@目标服务器IP:/path/to/deploy/
    - echo "代码同步完成!"
  when: on_success
配置说明:

tags: 确保与注册Runner时设置的标签匹配,这样任务才会分配到你的Runner。

only: 定义触发流水线的分支。

script 中的 rsync 命令:

-avz: 归档模式,verbose,压缩传输。

--delete: 同步时删除目标目录中源目录没有的文件(保持严格一致)。

--exclude: 排除不需要同步的目录或文件。

目标服务器用户名@目标服务器IP:/path/to/deploy/: 替换为你的实际服务器路径。

第五步:测试与验证
手动触发流水线:

在GitLab项目页面,进入 CI/CD → 流水线,点击 “运行流水线”。

或直接推送代码到 main 分支。

查看执行结果:

进入流水线详情页,查看 sync_to_server 任务的日志。

确认输出中显示 代码同步完成! 且无错误。

在CentOS服务器上安装已下载的三方.rpm文件(如GitLab 15.3.3-jh版本),需遵循依赖检查、权限控制、版本验证三大核心步骤,具体操作如下:
一、使用yum localinstall安装(推荐)
此命令会自动解决依赖关系并安装:
bash
sudo yum localinstall /path/to/gitlab-15.3.3-jh.rpm -y
-y参数表示自动确认所有提示,避免交互中断。
配置GitLab
编辑/etc/gitlab/gitlab.rb,设置external_url为新服务器域名或IP:
ruby
external_url 'https://新服务器域名或IP'
运行以下命令应用配置并启动服务:
bash
sudo gitlab-ctl reconfigure
sudo gitlab-ctl restart
检查服务状态
bash
sudo gitlab-ctl status # 所有服务应为run:状态
sudo gitlab-rake gitlab:check # 验证GitLab各项功能是否正常

二、从旧GitLab服务器备份数据
创建备份包:执行以下命令,GitLab将打包所有仓库、数据库、附件等数据。

bash
sudo gitlab-backup create
或者使用旧版命令:sudo gitlab-rake gitlab:backup:create。
备份文件默认生成在 /var/opt/gitlab/backups/ 目录下,文件名类似 1717411200_2025_06_02_15.3.3-jh_gitlab_backup.tar。

备份关键配置文件:这一步至关重要。备份命令不会包含这些配置文件,必须手动复制。

bash
sudo cp /etc/gitlab/gitlab.rb /etc/gitlab/gitlab-secrets.json /你的安全备份路径/
gitlab-secrets.json:包含数据库加密密钥、2FA秘密等,丢失将导致所有加密信息无法解密。

gitlab.rb:主配置文件。

三、迁移备份文件并恢复
传输文件:将备份文件和配置文件从旧服务器复制到新服务器。

bash
从旧服务器操作,将备份包传到新服务器的备份目录
scp /var/opt/gitlab/backups/备份文件名.tar 新服务器用户名@新服务器IP:/var/opt/gitlab/backups/
传输配置文件
scp /你的安全备份路径/gitlab-secrets.json /你的安全备份路径/gitlab.rb 新服务器用户名@新服务器IP:/tmp/
在新服务器上恢复:

停止相关服务:

bash
sudo gitlab-ctl stop unicorn
sudo gitlab-ctl stop sidekiq
恢复配置文件:

bash
sudo cp /tmp/gitlab-secrets.json /tmp/gitlab.rb /etc/gitlab/
执行恢复命令:BACKUP= 后面填写备份文件名的时间戳前缀(例如 1717411200_2025_06_02_15.3.3-jh)。

bash
sudo gitlab-backup restore BACKUP=备份文件的时间戳前缀
重新配置并启动:

bash
sudo gitlab-ctl reconfigure
sudo gitlab-ctl restart

四、验证迁移结果
打开浏览器,访问新服务器的 EXTERNAL_URL。

使用旧服务器的管理员账户登录。

检查所有用户、群组、项目、提交历史、议题、合并请求是否完整。

尝试进行代码拉取、推送等操作,确保仓库功能正常