MySQL索引数据结构原理
二叉树 - 链表结构 - 相当于全表扫描 大于自己的值,放在右边,比自己小的放在左边 红黑树 - 二叉平衡树 - 数据量大时,树的高度不可控 B-Tree树 非叶子节点也会存储数据 没有维护双向指针 树的高度 由非叶子节点 的叶叉树来决定的 16^n^ = 2Kw B+Tree - 多叉平衡树 B-Tree树的变种 树的高度可控 非叶子节点,作为一个冗余,不存储数据 1170 * 1170 * 16 = 2Kw 叶节点大小 16KB - 16384字节 Hash - hash运算 hashmap 桶 - 一次 I/O hash冲突 仅支持 = 等值,不支持范围查询 主键 必须有,否则MySQL会自行选择一列作为 聚簇索引,如果没有,MySQL 会做个 隐藏的 聚簇索引 且为整型 数值存储空间要小 数值比较效率要比字符串比较高 数值自增排序,避免页分裂 ASCII值 二级索引 - 非聚簇索引 回表&跳表 联合索引(复合索引) 最左前缀原则 ...
PHP 生命周期与 SAPI
一句话 PHP 生命周期 = MINIT → RINIT → 执行 → RSHUTDOWN → MSHUTDOWN。CLI/CGI 模式每个请求跑完整 5 步;FPM 模式只跑中间 3 步(M 阶段进程启动时跑一次);Swoole/Workerman 更进一步,只跑 1 步。 五大阶段 阶段 触发时机 典型工作 MINIT (Module Init) 进程启动 加载扩展、注册类/函数/常量 RINIT (Request Init) 每个请求开始 初始化 $_GET/$_POST/$_SESSION、扩展请求级状态 Execute RINIT 之后 把 PHP 源码编译成 opcode 并执行 RSHUTDOWN 请求结束 调注册的 shutdown 函数、清理临时变量 MSHUTDOWN 进程退出 卸载扩展、释放永久内存 CLI vs FPM vs SwooleCLI(每次都完整 5 步)1php script.php 启动:MINIT → RINIT → Execute → RSHUTDOWN...
require 与 include 的区别(含 _once)
一句话 require 失败 → Fatal Error(脚本停);include 失败 → Warning(脚本继续)。加 _once 后缀都能保证「只加载一次」。 核心对比 语句 找不到/解析失败 适用 require E_COMPILE_ERROR,脚本中止 必须加载的核心文件(配置、入口) require_once 同上,且多次调用只执行一次 函数/类定义(防重复声明报错) include E_WARNING,继续执行 可选模板片段(如可选侧栏) include_once 同上,且只加载一次 可选函数库 123require 'config.php'; // 没了直接死,应该死include 'sidebar.html'; // 没了页面少个边栏,能接受require_once 'User.php'; // class User 二次 require 会报 "Cannot redeclare" 一个最小验证1234// a....
依赖注入(DI)与 IoC 容器
一句话 依赖注入(Dependency Injection)= 一个类不自己创建依赖,而是由外部传入。IoC 容器 = 自动帮你完成”传入”这个动作的工厂 + 注册表。 一、问题:为什么不能自己 new123456class OrderService { private MysqlOrderRepo $repo; public function __construct() { $this->repo = new MysqlOrderRepo(new PDO(...)); // ❌ }} 毛病: 不可换实现 —— 想换 Redis?改源码 不可测 —— 单元测试想 mock 数据库?改不动 强耦合 —— OrderService 必须知道 PDO 的连接串 依赖隐藏 —— 看构造器看不出它依赖谁 二、三种注入方式1. 构造器注入(推荐)1234class OrderService { public function __construct(private O...
PHP 垃圾回收机制(GC)
一句话 PHP GC = 引用计数为主 + 循环引用收集器为辅。 引用计数归零立刻释放,解决不了的循环引用由后台收集器周期清理。 一、引用计数(refcount)PHP 的每个变量底层是 zval,里面有 refcount 和 is_ref 两个字段。 1234$a = 'hello'; // refcount = 1$b = $a; // refcount = 2 (写时复制,COW)unset($a); // refcount = 1unset($b); // refcount = 0 → 立即释放 用 xdebug_debug_zval() 或 debug_zval_refcount() 可以看到 refcount。 注意:PHP 7+ 的 zval 实现有重大改动(zval 嵌入栈、引用单独 zend_reference),但算法语义没变。 二、引用计数解决不了的:循环引用1234567891011class Node { public $next;}$a = new N...
Redis缓存
数据结构:memcache仅支持简单的key-value形式,Redis支持的数据更多(string字符串,set集合,list列表,hash散列,zset有序集合); 多线程:memcache支持多线程,Redis支持单线程 持久化:Redis支持持久化,memcache不支持持久化 分布式:Redis做主从结构,memcache服务器需要通过hash一致化来支撑主从结构 实际运用中可以redis,memcache结合,memcache可作为session存储的方式,session都是KV类型键值对。 Redis中,并不是所有的数据都一直存储在内存中的,这是和Memcache相比一个最大的区别。 Redis在很多方面具备数据库的特征,或者说就是一个数据库系统,而Memcache只是简单的K/V缓存。 他们的扩展都需要做集群;实现方式:master-slave、Hash。 在100k以上的数据中,Memcache性能要高于Redis。 如果要说内存使用效率,使用简单的key-value存储的话,Memcached的内存利用率更高,而如果Redis采用hash结...
Redis高并发
背景 Redis是不会存在并发问题的,因为他是单进程的,再多的命令都是一个接一个地执行的。 场景 GET & SET 利用Jedis等客户端对Redis进行并发访问 远程访问Redis的时候,因为网络等原因造成高并发访问、延迟返回 我们使用的时候,可能会出现并发问题,比如获得和设定这一对。 Redis的为什么 有高并发问题?Redis的的出身决定。 Redis是一种单线程机制的nosql数据库,基于key-value,数据可持久化落盘。 由于单线程所以Redis本身并没有锁的概念,多个客户端连接并不存在竞争关系, 但是利用Jedis等客户端对Redis进行并发访问时会出现问题。 原因 发生【连接超时】、【数据转换错误】、【阻塞】、【客户端关闭连接】等问题, 这些问题均是由于【客户端连接混乱】造成。 单线程的天性决定,高并发对同一个键的操作会排队处理, 如果并发量很大,可能造成后来的请求超时。 在远程访问Redis的时候,因为网络等原因造成高并发访问延迟返回的问题。 解决办法 客户端角度,将连接进行池化,同时对读写Redis操作采用内部锁 sy...
SQL查询语句的流程
当Mysql执行一条查询的SQl的时候大概发生了以下的步骤: 客户端发送查询语句给服务器。 服务器首先进行用户名和密码的验证以及权限的校验。 然后会检查缓存中是否存在该查询,若存在,返回缓存中存在的结果。若是不存在就进行下一步。注意:Mysql 8就把缓存这块给砍掉了。 接着进行语法和词法的分析,对SQl的解析、语法检测和预处理,再由优化器生成对应的执行计划。 Mysql的执行器根据优化器生成的执行计划执行,调用存储引擎的接口进行查询。服务器将查询的结果返回客户端。 Mysql中语句的执行都是都是分层执行,每一层执行的任务都不同,直到最后拿到结果返回,主要分为Service层和引擎层。 在Service层中包含:连接器、分析器、优化器、执行器。引擎层以插件的形式可以兼容各种不同的存储引擎,主要包含的有InnoDB和MyISAM两种存储引擎。具体的执行流程图如下所示:
MySQL - 锁
[TOC] 锁机制 计算机协调 多个进程或线程 并发访问某一资源的机制。 锁的类型及其特点开销、加锁、颗粒度、冲突、并发等角度分析 表级锁(table-level locking) 开销大,加锁快,不会出现死锁,颗粒度大,锁冲突概率高,并发度小; 页面锁(page-level locking) 开销、加锁效率、颗粒度介于表锁和行锁之间,会出现死锁,并发度一般; 行级锁(row-level locking) 开销大,加速慢,会出现死锁,颗粒度小,锁冲突概率小,并发度高; 锁的类型应用场景表锁 - 适合 以查询为主,只有少量按索引条件更新数据的应用,如web应用; 行锁 - 适合 大量按索引条件并发 更新少量不同数据,同时又有并发查询的应用,如在线事务处理系统; 锁的支持度及情况MyISAM 只支持 表锁 InnoDB 默认支持 行锁,也支持表锁 12-- 查询表锁争用情况show status like 'table%'; # Table_locks_waited 大则表锁争用情况严重 锁的维度划分共享锁(S) - 读锁 排他锁(X) - 写锁 意向共享锁...
MySQL 面试题速查
本文是浓缩版速答。每题尽量一句话讲清结论;详细原理点对应链接。 一、索引Q: 为什么 MySQL 用 B+ 树而不是 B 树/红黑树/Hash?B+ 树非叶节点不存数据 → 一个节点能装更多 key → 树更矮 → 磁盘 IO 少;叶子节点链表 → 范围查询快。Hash 不支持范围、不支持排序。 Q: 聚簇索引 vs 二级索引? 聚簇索引:叶子节点存整行数据,InnoDB 主键即聚簇索引 二级索引:叶子节点存主键值,需要”回表” Q: 什么是覆盖索引? → 详细SELECT 的字段全在二级索引里,不用回表。EXPLAIN 显示 Using index。 Q: 最左前缀原则?联合索引 (a, b, c) 只能命中 a / a+b / a+b+c,不能 b 或 b+c。 Q: 索引为什么会失效? → 12 种原因函数运算、隐式转换、%xxx、OR 含非索引列、违反最左前缀、负向查询… Q: 什么时候不该建索引? → 优缺点小表、低选择性字段、写多读少、字段经常更新。 二、事务与隔离级别Q: ACID 是什么? A 原子性:要么全做,要...




