Maison > Article > base de données > Un article pour vous aider à comprendre les principes sous-jacents de MYSQL
La colonne
L'exécution de la mise à jour démarre à partir de 客户端 => ··· => 执行引擎
C'est le même processus, vous devez d'abord retrouver ces données puis les mettre à jour. Pour comprendre le processus UPDATE
, jetons d’abord un coup d’œil au modèle architectural d’Innodb.
Dernier schéma d'architecture InnoDB officiel MYSQL :
Connecteur (JDBC, ODBC, etc.) =>
[MYSQL Interne
[Connection Pool] (授权、线程复用、连接限制、内存检测等) => [SQL Interface] (DML、DDL、Views等) [Parser] (Query Translation、Object privilege) [Optimizer] (Access Paths、 统计分析) [Caches & Buffers] => [Pluggable Storage Engines]复制代码
]
=> [Fichier]
Là est un point clé ici. Lorsque nous interrogeons les données, nous prendrons d'abord le page
que nous interrogeons actuellement et irons à buffer pool
pour vérifier si 当前page
est dans 缓冲池
. Si c'est le cas, obtenez-le directement.
et si c'est update操作
, la valeur en Buffer
sera modifiée directement. À l'heure actuelle, les données dans buffer pool
sont les mêmes que les données réellement stockées sur notre disque 不一致
, qui s'appelle 脏页
. De temps en temps, le moteur de stockage Innodb videra 脏页数据
sur le disque. De manière générale, lors de la mise à jour d'une donnée, nous devons lire les données dans buffer
pour les modifier, puis les réécrire sur le disque pour terminer une opération 落盘IO
.
Afin d'améliorer les performances de fonctionnement de update
, Mysql a été optimisé en mémoire. Comme vous pouvez le constater, il y a une zone dans 架构图的缓冲池
appelée : change buffer
. Comme son nom l'indique, 给change后的数据,做buffer的
, lors de la mise à jour d'une donnée sans unique index
, placez directement les données modifiées dans change buffer
, puis terminez la mise à jour via l'opération merge
, réduisant ainsi l'opération 落盘的IO
.
没有唯一索引的数据更新时
, pourquoi 没有唯一索引的数据更新时
doit-il être placé directement dans change buffer
? S'il y a 唯一约束的字段
, après avoir mis à jour les données, les données mises à jour peuvent dupliquer les données existantes, de sorte que le caractère unique ne peut être déterminé qu'à partir du disque 把所有数据读出来比对
. 写多读少
, nous pouvons ajuster la proportion de innodb_change_buffer_max_size
dans change buffer
en ajoutant buffer pool
La valeur par défaut est 25 (soit : 25%) Il y a quatre situations :
redo log
Lorsqu'il est plein, fusionnez avec le disqueQuand il s'agit de refaire, nous devons parler de crash safe
d'Innodb, qui est implémenté à l'aide de WAL (write Ahead Logging, enregistrez le journal avant d'écrire)
De cette façon, lorsque la base de données plante, les données peuvent être restaurées directement à partir de redo log
pour garantir l'exactitude des données
Le journal redo est stocké dans deux fichiers par défaut ib_logfile0
. Ces deux fichiers sont ib_logfile1
. Pourquoi avez-vous besoin d'une taille fixe ? 固定大小的
de redo log
, qui doit être un espace de stockage continu 顺序读取
En fait, indépendamment de la mécanique ou du solide état, quand nous allons au magasin, ils traitent tous le disque via 文件系统
, et ils le traitent de deux manières. 随机读写
et 顺序读写
块
(par défaut 1bloc=8 secteurs=4K) 一串连续的块
, la vitesse de lecture est donc grandement améliorée Voir le buffer pool
dans Log Buffer
, qui est le tampon qui existait avant d'écrire le redo log
Ici, il existe trois stratégies d'exécution spécifiques pour le redo log :
Log Buffer
. Il vous suffit d'écrire les données du disque de rétablissement une fois par seconde. Les performances sont élevées, mais cela entraînera des problèmes de cohérence des données en 1 seconde. Applicable à 强实时性
, 弱一致性
, comme 评论区评论
Log Buffer
et écriture sur disque en même temps, avec les pires performances et la cohérence la plus élevée. Applicable à 弱实时性
, 强一致性
, tel que 支付场景
Log Buffer
et écrit sur os buffer
en même temps (il appellera fsync
toutes les secondes pour vider les données sur le disque ), avec de bonnes performances. La sécurité est également élevée. Il s'agit de 实时性适中
一致性适中
, tel que 订单类
. Nous pouvons définir la stratégie d'exécution via innodb_flush_log_at_trx_commit
. La valeur par défaut est 1
自适应Hash索引
est principalement utilisé pour accélérer les requêtes 页
. Lors de l'interrogation, Innodb détermine si la requête en cours peut aller Hash索引
en surveillant le mécanisme de recherche d'index. Par exemple, l'opérateur LIKE et le caractère générique % ne peuvent pas être utilisés. est stocké dans un fichier appelé ibdata1
, qui contient :
Buffer Pool
écrit une page de données, elle n'est pas écrite directement dans le fichier, mais d'abord dans cette zone. L'avantage de ceci est qu'une fois le système d'exploitation, le système de fichiers ou MySQL bloqué, les données peuvent être obtenues directement à partir de ce Buffer
. Chaque table possède un fichier .ibd
pour stocker les données et les index.
每表文件表空间
, les performances de ALTER TABLE
et TRUNCATE TABLE
peuvent être grandement améliorées. Par exemple, ALTER TABLE
sera effectué lors de la modification d'une table par rapport à une table résidant dans un espace table partagé, ce qui peut augmenter le 表复制操作
occupé par l'espace table. De telles opérations peuvent nécessiter autant d'espace supplémentaire que les données de la table et des index. L'espace n'est pas libéré vers le système d'exploitation comme 磁盘空间量
. 每表文件表空间
Drop table
(sauf si vous gérez vous-même la fragmentation) fsync
vider les données dans le fichier en même temps 文件句柄
de chaque fichier de table pour fournir un accès continu au fichier 共享表空间
Il peut stocker des 多个表
données每表表空间
小
sont stockés dans un fichier appelé ibtmp1
. Dans des circonstances normales, Mysql créera un espace table temporaire au démarrage et supprimera l'espace table temporaire à l'arrêt. Et il peut s'étendre automatiquement.
原子性
, c'est-à-dire que lorsqu'une exception se produit au milieu d'une modification, vous pouvez revenir en arrière dans le journal d'annulation. 系统表空间``撤销表空间``临时表空间
, comme indiqué dans le diagramme d'architecture. Comme mentionné précédemment
origin
, est renvoyée à l'exécuteur modification
modification
Buffer Pool
Change Buffer
, Undo
et d'ailleurs Redo
.Bin log
innodb
est dans Bin log
. Il peut donc être utilisé par tous les moteurs 服务层
Bin log
déclaration sous la forme d'un événement. C'est un journal au sens logique. DDL DML
主从复制
obtient le journal 从
du serveur 主
puis l'exécute. bin log
数据恢复
索引
InnoDB中的索引
文件存储级别
Stockage de fichiers Innodb Divisé en quatre niveaux
Leur relation est :
Par défaut La taille deextent
morceaux de 1M
. La taille de page généralement mentionnée par notre système de fichiers est 64
, contenant 16KB
Page
secteurs. 4KB
8
512Byte
Structure de stockage B tree variante B+ tree Donc parfois, on nous demande pourquoi la clé primaire doit être commandée, c'est-à-dire si nous. Sur un champ ordonné, créez un index puis insérez des données. Lors du stockage, innodb les stockera sur un par un dans l'ordre lorsqu'une page est pleine, il demandera une nouvelle page, puis continuera à enregistrer.
Mais si nos champs ne sont pas ordonnés, les emplacements de stockage seront sur des pages différentes. Lorsque nos données sont stockées sur un 页
qui a été
, formant ainsi 存满
. 页
B+树
figure ci-dessus, 行数据
est stocké sur le nœud enfant, et les index 排列的顺序
et 索引键值顺序
S'ils sont cohérents, c'est 聚簇索引
. L'index de clé primaire est un index clusterisé. À l'exception de l'index de clé primaire, tous les autres sont des 辅助索引
辅助索引
, seuls 自己的值
et 主键索引的值
sont stockés sur. ses nœuds feuilles. Cela signifie que si nous interrogeons toutes les données via l'index auxiliaire, nous rechercherons d'abord 辅助索引
dans 主键键值
, puis irons dans 主键索引
pour trouver le 数据
associé. Ce processus s'appelle 回表
rowid
Et s'il n'y a pas de 主键索引
? 聚簇索引
sera créé sur la base de cette clé. rowid
et le crée en fonction de cet identifiant 聚簇索引
Après avoir compris ce qu'est un index et quelle est sa structure. Voyons quand nous devons utiliser des index. Les comprendre peut mieux nous aider à créer des index corrects et efficaces
Ne créez pas d'index si la dispersion est faible, c'est-à-dire les données. S’il n’y a pas beaucoup de différence entre eux, il n’est pas nécessaire de créer un index. (En raison de la création de l'index, lors de l'interrogation, la plupart des données dans innodb sont les mêmes. Si je vais à l'index et qu'il n'y a aucune différence entre la table entière, ce sera 全表查询
directement). Par exemple, le domaine du genre. Cela gaspille beaucoup d’espace de stockage.
index de champ commun, tel que idx(name, class_name)
select * from stu where class_name = xx and name = lzw
, l'index idx
peut également être utilisé, car le optimiseur Optimiser SQL pour name = lzw and class_name = xx
select ··· where name = lzw
est nécessaire, il n'est pas nécessaire de créer un index name
séparé. L'index idx
覆盖索引
sera. utilisé directement. Si tous les 所有数据
que nous interrogeons cette fois sont inclus dans l'index, il n'est plus nécessaire d'interroger 回表
. Par exemple : select class_name from stu where name =lzw
index_condition_pushdown)
select * from stu where name = lzw and class_name like '%xx'
索引条件下推
, car il est suivi de la condition de requête de like '%xx'
, donc ici on passe d'abord par name
basé sur idx联合索引
pour interroger plusieurs données, puis 回表
pour interroger 全量row数据
, et puis procédez dans server层
Si les données trouvées par le filtrage des likes sont 引擎层
, ce qui équivaut à effectuer l'server层
opération de filtrage 下推到引擎层
. Comme le montre la figure : 页分裂
, l'index est stocké dans l'ordre. Si la page de stockage est pleine, son insertion à nouveau entraînera des fractionnements de page. ) 函数
comme replace, sum, count, etc., l'index ne sera pas utilisé, il n'est donc pas nécessaire de créer un select count(distinct left(name, 10))/count(*)
pour voir la dispersion et décider. pour extraire les premiers chiffres) 优化器决定的
. Par exemple, si vous utilisez l'optimiseur basé sur les coûts Cost Base Optimizer
, utilisez l'optimisation ayant le coût le plus bas. Une autre magnifique ligne de démarcation
Passons d'abord en revue quelques concepts de base que nous connaissons :
Prérequis, dans une transaction :
La norme SQL92 stipule : (La concurrence diminue de gauche à droite)
Ces deux solutions sont utilisées ensemble dans Innodb. Voici une brève explication de RR 的 MVCC实现
. La valeur initiale de l'identifiant de restauration dans la figure ne doit pas être 0 mais NULL Pour plus de commodité, elle est écrite sous la forme 0
RC的MVCC实现是对 同一个事务的多个读 创建一个版本
RR 是 同一个事务任何一条都创建一个版本
En combinant MVCC
avec LBCC
, InnoDB peut résoudre la situation de lecture fantôme dans 不加锁
conditions. Au lieu de devoir laisser la transaction Serializable
se dérouler comme 串行
, sans aucun 并发
.
Examinons en profondeur comment InnoDB锁
implémente le RR
niveau d'isolation des transactions
表级别
est 四把锁
最基本锁的类型
Considérons-les temporairement ici. Ils sont appelés : 四把锁
高阶锁
2. Explication détaillée des verrous en lecture-écriture
Pour utiliser les verrous partagés, après l'instruction Ajoutezlock in share mode
après la déclaration. Insert、Update、Delete
for update
Les verrous d'intention sont maintenus par la base de données elle-même. (La fonction principale est de donner à la table 打一个标记
Nous avons parlé de l'existence des index ci-dessus. Passons en revue ici. Il existe plusieurs situations :
Vous avez créé une clé primaire, qui est un index clusterisé (qui stocke).完整的数据
Il n'y a pas de clé primaire, mais il y a une clé unique. Si aucune n'est nulle, elle sera créée sur la base de cette clé 聚簇索引
Si vous ne le faites pas. Si vous n'avez ni l'un ni l'autre des éléments ci-dessus, ne vous inquiétez pas, innodb lui-même maintient quelque chose appelé rowid
聚簇索引
Lorsque vous effectuez
sur une table pour laquelle vous n'avez pas explicitement créé, la base de données ne sait en fait pas quelles données rechercher et la table entière peut être utilisée. Alors juste 索引
. 加锁查询
辅助索引
, par exemple, select * from where name = ’xxx‘ for update
doit enfin 回表
vérifier les informations sur la clé primaire, donc à ce moment, en plus du verrouillage 辅助索引
, vous devez également verrouiller 主键索引
Tout d'abord, parlons de trois concepts. Il existe un tel ensemble de données. : la clé primaire est 1, 3, 6, 9 Lors du stockage, il se présente comme suit : x 1 x 3 x x 6 x x x 9 x... Gap lock, verrouille l'espace d'enregistrement, chacun
, (-∞,1), (1,3), (3,6), (6,9), (9,+∞) Lors du verrouillage, ce qui est verrouillé est (-∞,1], (1,3], (3,6], (6,9], (9,+∞], l'intervalle ouvert à gauche et fermé à droitex
d'abord Ces trois types de verrous sont tous
排它锁
select * from xxx where id = 3 for update
est généré lorsque select * from xxx where id = 5 for update
, un verrou de clé temporaire est généré =. > lock. (3,6], mysql utilise des verrous à clé temporaires par défaut. Si les conditions 1 et 2 ne sont pas remplies, tous les verrous de ligne sont des verrous à clé temporaires select * from xxx where id = 5 for update
Record Lock 行锁
problème de lecture fantôme lors de l'écriture des données Gap Lock 间隙锁
. 🎜>Gap Lock 和 Record Lock
Quand il s'agit de verrous, nous devons parler de blocages Next-Key锁
RR级别
Vérifier après un blocageshow status like 'innodb_row_lock_%'
InnoDB_ROW_LOCK_TIME_AVG moyenne select * from information_schema.INNODB_TRX
de show full processlist
select * from information_schema.processlist
Prévention des blocages 哪个用户
在哪台机器host的哪个端口上
连接哪个数据库
Garantir l'ordre d'accès aux données 执行什么指令
状态与时间
Évitez d'utiliser l'index lors de l'utilisation de Where (Cela verrouillera la table, ce qui non seulement rendra les blocages plus probables se produit, mais diminue également les performances) 1. Pool de connexions client
Ajouter un pool de connexions à. évitez-le à chaque foisAlors plus nous avons de pools de connexions, mieux c'est ? Les amis intéressés peuvent lire cet article : À propos du dimensionnement de la piscine
Je vais le résumer grossièrement : 查询执行过程
CPU
peut réellement exécuter 线程
. Parce que le système d'exploitation utilise la technologie 时间分片
, cela nous fait penser qu'un CPU内核
a exécuté 多个线程
. CPU
précédent ne peut en exécuter qu'un seul 时间段
à un certain 线程
, donc peu importe la façon dont nous augmentons la simultanéité, CPU
ne peut toujours traiter qu'une quantité limitée de données pendant cette période période. CPU
ne peut pas traiter autant de données, pourquoi va-t-il ralentir ? Parce que 时间分片
, lorsque plusieurs threads semblent être dans "同时执行"
, en fait, le 上下文切换
entre eux prend beaucoup de temps I/O
À ce moment, CPU
peut découper le temps vers un autre , pour améliorer l'efficacité et la vitesse du traitement线程
I/O
线程数 = ((核心数 * 2) + 有效磁盘数)
machine vaut 4 * 2 + 1 = 9 i7 4core 1hard disk
很多CPU计算和I/O的场景
Redis
读写分离
. 异步复制
Binary Log
, relay log
enregistrera la dernière lecture slave
à Binary Log Position
, et commencera directement à partir de cet endroit la prochaine fois. Allez le chercher. master info
réplication maître-esclave ci-dessus est qu'elle n'est pas mise à jour à temps. Lorsqu'une donnée est écrite et immédiatement lue par un utilisateur, les données lues sont toujours les données précédentes, ce qui signifie qu'il y a un délai.
Pour résoudre le problème de retard, vous devez introduire 异步
事务
failover
impactant les performances锁操作
est activé show_query_log
, et SQL dont le temps d'exécution dépasse la variable long_query_time
sera enregistré.
Vous pouvez utiliser mysqldumpslow /var/lib/mysql/mysql-slow.log
, et il existe de nombreux plug-ins qui peuvent fournir une analyse plus élégante que celle-ci, je n'entrerai donc pas dans les détails ici.
Tout SQL doit être explain
révisé
left/right join
entraîne de faibles performances left/right join
spécifiera directement la table des pilotes Dans MYSQL, Nest loop join
est utilisée par défaut. pour l'association de tables (c'est-à-dire via L'ensemble de résultats de 驱动表
est utilisé comme données de base du cycle, puis les données de la table associée suivante sont filtrées à travers chaque élément de données de cet ensemble, et enfin les résultats sont fusionnés pour obtenir ce que l'on appelle souvent 临时表
). 驱动表
sont au niveau 百万千万
, vous pouvez imaginer à quel point cette requête de table commune sera lente. Mais à l'inverse, si 小表
est utilisé comme 驱动表
, la requête 千万级表
à l'aide de 索引
peut devenir très rapide. 驱动表
, veuillez laisser l'optimiseur décider, par exemple : select xxx from table1, table2, table3 where ···
, l'optimiseur utilisera la table avec un petit nombre de lignes d'enregistrement de requête comme table de conduite. 驱动表
vous-même, veuillez tenir l'arme Explain
Parmi les résultats de Explain
, le premier est trié par 基础驱动表
表
. Nous essayons de trier 驱动表
au lieu de 临时表,也就是合并后的结果集
. Autrement dit, si using temporary
apparaît dans le plan d'exécution, il doit être optimisé. 普通查询
et 复杂查询
(requête conjointe, sous-requête, etc. .) SIMPLE
, la requête ne contient pas de sous-requêtes ou UNIONPRIMARY
Si la requête contient la sous-structure de 复杂查询
, alors vous devez utiliser la requête de clé primaire. SUBQUERY
, inclure select
where
子查询
DERIVED
, inclure la sous-requête from
UNION RESULT
, interroger la sous-requête from union
table 越来越快
const或者system
Analyse à niveau constant, le moyen le plus rapide d'interroger une table, le système est un cas particulier de const (il n'y a qu'une seule donnée dans la table) eq_ref
Analyse d'index uniqueref
Analyse d'index non unique range
Analyse de plage d'index, telle qu'entre, et d'autres requêtes de plage index
(index complet) scan Tous les arbres d'index ALL
Scannez la table entière NULL
, pas besoin d'accéder à la table ou à l'index 不一定使用
哪一个索引被真正使用
est arrivée. NULL si non disponible 索引(key)
only index
Les informations doivent uniquement être obtenu à partir de l'index On constate qu'un index de couverture peut être utilisé, et la requête est très rapide using where
Si la requête n'utilise pas d'index, elle sera filtrée au niveau de la couche server
et puis utilisez where
pour filtrer l'ensemble de résultats impossible where
Rien n'a été trouvé using filesort
, tant qu'il n'est pas trié par index, mais que d'autres méthodes de tri sont utilisées, il est un tri de fichiersusing temporary
(cela doit être fait via une table temporaire Stocker temporairement l'ensemble de résultats puis effectuer des calculs) De manière générale, dans ce cas, DISTINCT、排序、分组
using index condition
Le push-down d'index est effectué. Comme mentionné ci-dessus, cela est effectué par server层
Opération de filtrage 下推到引擎层
插入与查询
Moteur de stockage MyISAM
memory
插入、更新、查询
InnoDB
Recommandations d'apprentissage gratuites associées : Tutoriel vidéo MySQL
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!