¿Por qué MySQL usa árboles B+ como índices?

Hola a todos, mi nombre es Xiaolin.

"¿Por qué MySQL usa el árbol B+ como índice?" ¿Aparece esta oración a menudo en las entrevistas?

Para explicar este problema, de hecho, no solo desde la perspectiva de la estructura de datos, sino también del número de operaciones de E/S del disco, porque los datos de MySQL se almacenan en el disco.

Esta vez, analizaré este problema con usted capa por capa. La imagen contiene muchas imágenes en movimiento para ayudar a todos a comprender. ¡Creo que después de leerlo, comprenderá este tema!

imagen

¿Qué tipo de estructura de datos indexados es buena?

Los datos de MySQL son persistentes, lo que significa que los datos (índice + registro) se guardan en el disco, porque incluso si el dispositivo está apagado, los datos no se perderán.

El disco es un dispositivo de almacenamiento ridículamente lento, ¿qué tan ridículo es eso?

La velocidad de acceso a la memoria de otras personas es en nanosegundos, mientras que la velocidad de acceso al disco es en milisegundos, es decir, al leer datos del mismo tamaño, la velocidad de lectura del disco es decenas de miles de veces más lenta que la de leyendo de memoria. , incluso cientos de miles de veces.

La unidad mínima de lectura y escritura en un disco es un sector y el tamaño de un sector es solo el 512Btamaño El sistema operativo leerá y escribirá varios sectores a la vez, por lo que la unidad mínima de lectura y escritura del sistema operativo es un bloque. El tamaño del bloque en Linux es4KB de 8 sectores, lo que significa que una operación de E/S de disco leerá y escribirá directamente 8 sectores.

Dado que el índice de la base de datos se guarda en el disco, cuando buscamos una fila de datos a través del índice, primero debemos leer el índice del disco a la memoria y luego encontrar una fila de datos del disco a través del index, y luego léalo en la memoria. , es decir, se producirán múltiples E/S de disco durante el proceso de consulta, y cuantas más E/S de disco, mayor será el tiempo consumido.

Por lo tanto, esperamos que la estructura de datos indexada pueda completar el trabajo de consulta en la menor cantidad posible de operaciones de E/S de disco, porque cuantas menos operaciones de E/S de disco se consuman, menos tiempo.

Además, MySQL admite búsquedas de rango, por lo que la estructura de datos del índice no solo debe poder consultar de manera eficiente un determinado registro, sino también realizar búsquedas de rango de manera eficiente.

Por lo tanto, para diseñar una estructura de datos adecuada para el índice MySQL, se cumplen al menos los siguientes requisitos:

  • El trabajo de consulta se puede completar en la menor cantidad posible de operaciones de E/S de disco;
  • Para poder consultar un registro de manera eficiente, también debe poder realizar búsquedas de rango de manera eficiente;

Después de analizar los requisitos, analizamos cada estructura de datos.

¿Qué es la búsqueda binaria?

Los datos del índice se organizan mejor en orden, de modo que el "método de búsqueda binaria" se pueda utilizar para localizar los datos de manera eficiente.

Supongamos que ahora usamos una matriz para almacenar el índice. Por ejemplo, hay una matriz ordenada a continuación. Si queremos encontrar el número 3, la forma más fácil es recorrer la consulta desde el principio. La complejidad temporal de este método es O (n), y la eficiencia de la consulta no es alta. Debido a que la matriz está ordenada, podemos usar el método de búsqueda binaria, como el siguiente diagrama de proceso de consulta que usa el método binario:

imagen

Se puede ver que el método de búsqueda binaria reduce a la mitad el rango de la consulta cada vez, de modo que la complejidad del tiempo se reduce a O (logn), pero cada búsqueda necesita calcular continuamente la posición media.

¿Qué es un árbol de búsqueda binaria?

El uso de matrices para implementar datos ordenados linealmente es simple y fácil de usar, pero el rendimiento es demasiado bajo al insertar nuevos elementos.

Debido a que insertar un elemento requiere cambiar todos los elementos después de este elemento en uno, ¿qué pasa si esta operación ocurre en el disco? Esto debe ser catastrófico. Debido a que el disco es cientos de miles de veces más lento que la memoria, no podemos ordenar el disco con una estructura lineal.

En segundo lugar, cuando se utiliza la búsqueda binaria para matrices ordenadas, la posición media debe calcularse continuamente para cada búsqueda.

Entonces, ¿podemos diseñar una estructura de datos no lineal que sea naturalmente adecuada para la búsqueda binaria?

Sí, vea la operación mágica en la figura a continuación, encuentre todos los nodos intermedios utilizados en todas las búsquedas binarias, conéctelos con punteros y use el nodo más intermedio como nodo raíz.

Por favor agregue la descripción de la imagen

¿Qué tal? Se ha convertido en un árbol binario, pero no es un árbol binario ordinario, es un árbol de búsqueda binaria .

La característica de un árbol de búsqueda binario es que todos los nodos en el subárbol izquierdo de un nodo son más pequeños que este nodo, y todos los nodos en el subárbol derecho son más grandes que este nodo , por lo que cuando consultamos datos, no necesitamos calcular el posición de los nodos intermedios, simplemente compare los datos de búsqueda con los datos del nodo.

Supongamos que encontramos el nodo cuyo valor de índice es clave:

  1. Si la clave es mayor que el nodo raíz, busque en el subárbol derecho;
  2. Si la clave es menor que el nodo raíz, busque en el subárbol izquierdo;
  3. Si la clave es igual al nodo raíz, es decir, se encuentra el nodo y se puede devolver el nodo raíz.

La demostración animada de encontrar un nodo en un árbol de búsqueda binaria es la siguiente, por ejemplo, para encontrar el nodo 3:

imagen

Además, el árbol de búsqueda binaria resuelve el problema de insertar nuevos nodos, porque el árbol de búsqueda binaria es una estructura de salto y no tiene que organizarse consecutivamente. De esta manera, al insertar, el nuevo nodo se puede colocar en cualquier posición, en lugar de insertar un elemento como una estructura lineal, todos los elementos deben organizarse al revés.

La siguiente es una demostración animada de la inserción de un nodo en un árbol de búsqueda binaria:

Por favor agregue la descripción de la imagen

Por lo tanto, el árbol de búsqueda binario resuelve el problema del alto costo de insertar nuevos elementos en una estructura continua, manteniendo la estructura binaria natural.

¿Es ese un árbol de búsqueda binario que se puede usar como una estructura de datos indexada?

No, no, ¡hay un caso extremo de un árbol de búsqueda binaria que hará que se vuelva cojo!

Cuando el elemento insertado cada vez es el elemento más grande en el árbol de búsqueda binaria, el árbol de búsqueda binaria degenerará en una lista enlazada, y la complejidad temporal de encontrar datos se convierte en O(n) , como se muestra en la siguiente animación:

Por favor agregue la descripción de la imagen

Dado que el árbol se almacena en el disco, acceder a cada nodo corresponde a una operación de E/S de disco ( suponiendo que el tamaño de un nodo es "menor" que el tamaño del bloque de unidad de lectura-escritura más pequeño del sistema operativo ), que es decir , la altura del árbol es igual a Es igual al número de operaciones de E/S del disco cada vez que se consultan los datos , por lo que cuanto mayor sea la altura del árbol, el rendimiento de la consulta se verá afectado.

Debido a la posibilidad de degenerar un árbol de búsqueda binario en una lista enlazada, la complejidad temporal de la operación de consulta se reducirá de O(logn) a O(n).

Además, a medida que se insertan más elementos, la altura del árbol también aumentará, lo que significa que se requieren más operaciones de E/S de disco, lo que provocará una caída importante en el rendimiento de las consultas. Además, las consultas de rango no se pueden utilizar, por lo que es no apto para su uso como índice de base de datos.

¿Qué es un árbol binario autoequilibrado?

Para resolver el problema de que el árbol de búsqueda binaria degenerará en una lista enlazada en casos extremos, más adelante se propuso un árbol de búsqueda binaria equilibrada (árbol AVL) .

Principalmente, se agregan algunas restricciones condicionales sobre la base del árbol de búsqueda binaria: la diferencia de altura entre el subárbol izquierdo y el subárbol derecho de cada nodo no puede exceder 1 . Es decir, el subárbol izquierdo y el subárbol derecho del nodo siguen siendo árboles binarios equilibrados, por lo que la complejidad temporal de la operación de consulta siempre se mantendrá en O(logn).

La siguiente figura muestra que el elemento insertado cada vez es el elemento más grande en el árbol de búsqueda binaria balanceada, como puede ver, mantendrá el autobalanceo:

imagen

Además de los árboles de búsqueda binarios equilibrados, existen muchos árboles binarios autoequilibrados, como los árboles rojo-negro, que también logran el autoequilibrio a través de algunas restricciones. Sin embargo, las restricciones de los árboles rojo-negro son más complicadas y no son las enfoque de este artículo Puede ver libros relacionados con "Estructuras de datos" para comprender las restricciones de los árboles rojo-negro.

El siguiente es el proceso de inserción de nodos en el árbol rojo-negro. Esta operación de zurdos y diestros es para el autoequilibrio.

imagen

Independientemente de si se trata de un árbol de búsqueda binario equilibrado o un árbol rojo-negro, a medida que aumenta la cantidad de elementos insertados, la altura del árbol aumentará, lo que significa que la cantidad de operaciones de E/S del disco es grande, lo que afectará la eficiencia de la consulta de datos en general .

Por ejemplo, si la altura del árbol de búsqueda binario balanceado a continuación es 5, entonces se requieren 5 operaciones de E/S de disco para acceder al nodo inferior.

imagen

La razón fundamental es que todos son árboles binarios, es decir, cada nodo solo puede guardar 2 nodos hijos, ¿y si cambiamos el árbol binario a un árbol M-ario (M>2)?

Por ejemplo, cuando M=3, en el caso del mismo número de nodos, la altura del árbol del árbol ternario es menor que la del árbol binario.

imagen

Por lo tanto, cuando hay más nodos en el árbol y el número de ramas M del árbol es mayor, la altura del árbol bifurcado en M será mucho menor que la altura del árbol binario .

¿Qué es un árbol B?

Aunque el árbol binario autoequilibrado puede mantener la complejidad temporal de la operación de consulta en O(logn), debido a que es esencialmente un árbol binario, cada nodo solo puede tener 2 nodos secundarios, luego, cuando el número de nodos es mayor, la altura del árbol También aumentará en consecuencia, lo que aumentará la cantidad de E/S de disco, lo que afectará la eficiencia de la consulta de datos.

Para resolver el problema de reducir la altura del árbol, apareció más tarde el árbol B, que ya no restringe un nodo a solo 2 nodos secundarios, sino que permite M nodos secundarios (M>2), reduciendo así la altura del árbol.

Cada nodo del árbol B puede incluir como máximo M subnodos, y M se llama el orden del árbol B, por lo que el árbol B es un poliárbol.

Suponiendo que M = 3, entonces es un árbol B de orden 3, que se caracteriza porque cada nodo tiene como máximo 2 (M-1) datos y como máximo 3 (M) nodos secundarios. Si se superan estos requisitos, se ser nodos divididos, como la siguiente animación:

imagen

Echemos un vistazo al proceso de consulta de un árbol B de tercer orden.

imagen

Supongamos que estamos buscando un registro con un valor de índice de 9 en un árbol B de tercer orden en la figura anterior, entonces los pasos se pueden dividir en los siguientes pasos:

  1. Compare con el índice (4, 8) del nodo raíz, si 9 es mayor que 8, luego vaya al nodo secundario a la derecha;
  2. Entonces el índice del nodo hijo es (10, 12), porque 9 es menor que 10, irá al nodo hijo izquierdo del nodo;
  3. Vaya al nodo con índice 9 y luego encontramos el nodo con valor de índice 9.

Se puede ver que cuando un árbol B de tercer orden consulta los datos en los nodos hoja, dado que la altura del árbol es 3, se producirán tres operaciones de E/S de disco durante el proceso de consulta.

Y si el mismo número de nodos está en el escenario de un árbol binario balanceado, la altura del árbol será muy alta, lo que significa más operaciones de E/S de disco. Por lo tanto, B-tree es más eficiente que el árbol binario equilibrado en la consulta de datos.

Sin embargo, cada nodo del árbol B contiene datos (índice + registro), y es probable que el tamaño de los datos de registro del usuario supere con creces los datos del índice, lo que requiere más operaciones de E/S del disco para leer "Datos de índice útiles".

Además, en el proceso de consulta de un nodo en la parte inferior (como un registro A), los datos de registro en el "nodo de registro no A" se cargarán del disco a la memoria, pero estos datos de registro son inútiles, solo queremos leer Los datos de índice de estos nodos se utilizan para comparación y consulta, y los datos de registro en el "nodo de registro no A" no nos sirven, lo que no solo aumenta la cantidad de operaciones de E/S de disco, sino que también ocupa recursos de memoria .

Además, si usa el árbol B para la consulta de rango, necesita usar el recorrido en orden, lo que implicará problemas de E/S de disco de múltiples nodos, lo que resultará en una disminución de la velocidad general.

¿Qué es un árbol B+?

El árbol B+ es una actualización del árbol B. La estructura de datos del índice en MySQL utiliza el árbol B+. La estructura del árbol B+ es la siguiente:

imagen

Las diferencias entre el árbol B+ y el árbol B son principalmente los siguientes puntos:

  • Solo el nodo hoja (el nodo inferior) almacenará los datos reales (índice + registro), y el nodo que no es hoja solo almacenará el índice;
  • Todos los índices aparecerán en los nodos hoja y se formará una lista enlazada ordenada entre los nodos hoja;
  • El índice del nodo que no es hoja también existe en el nodo secundario y es el más grande (o el más pequeño) de todos los índices del nodo secundario.
  • Hay tantos índices como nodos secundarios en un nodo no hoja;

Los tres aspectos siguientes comparan las diferencias de rendimiento entre los árboles B+ y B.

1. Consulta de un solo punto

Cuando B-tree realiza una consulta de índice único, se puede encontrar con el costo de tiempo más rápido de O(1) y, en términos de costo de tiempo promedio, será un poco más rápido que el árbol B+.

Sin embargo, la fluctuación de consultas de B-tree será relativamente grande, porque cada nodo almacena tanto el índice como el registro, por lo que a veces se puede acceder al nodo que no es hoja para encontrar el índice, y a veces se necesita acceder al nodo hoja para encontrar el índice.

Los nodos que no son hojas del árbol B+ no almacenan los datos de registro reales, sino solo los índices. Por lo tanto, cuando la cantidad de datos es la misma, los nodos que no son hojas del árbol B+ pueden almacenar más índices que los nodos B- árbol que almacena tanto índices como registros. , por lo que el árbol B+ puede ser más "grueso" que el árbol B, y la cantidad de E/S de disco para consultar los nodos subyacentes será menor .

2. Eficiencia de inserción y eliminación

El árbol B+ tiene una gran cantidad de nodos redundantes, por lo que cuando se elimina un nodo, se puede eliminar directamente de los nodos de hoja, e incluso los nodos que no son de hoja se pueden mover, por lo que la eliminación es muy rápida.

Por ejemplo, la siguiente animación es el proceso de eliminación del nodo 0004 del árbol B+, y la estructura del árbol cambia muy poco:

Por favor agregue la descripción de la imagen

Nota: el árbol B+ puede tener diferentes definiciones para el número de nodos secundarios y los índices de los nodos que no son hojas. Algunos dicen que el número de nodos secundarios de los nodos que no son hojas es de orden M, y el número de índices es M-1 ( Esta es la definición en Wikipedia), por lo que mis animaciones sobre árboles B+ en este artículo se basan en esto. Pero cuando presenté la diferencia entre el árbol B+ y el árbol B+, dije que "hay tantos nodos secundarios como nodos que no son hojas, hay tantos índices", principalmente porque el árbol B+ utilizado por MySQL es este rasgo.

La siguiente animación es el proceso de eliminación del nodo 0008 del árbol B, lo que puede generar cambios complejos en el árbol:
Por favor agregue la descripción de la imagen

Incluso cuando el árbol B+ elimina el nodo raíz, debido a la existencia de nodos redundantes, no se producirá una deformación compleja del árbol. Por ejemplo, la siguiente animación es el proceso de eliminación del nodo raíz del árbol B+:

Por favor agregue la descripción de la imagen

El árbol B es diferente. El árbol B no tiene nodos redundantes. Es muy complicado eliminar nodos. Por ejemplo, eliminar los datos en el nodo raíz puede implicar una deformación compleja del árbol. Por ejemplo, la siguiente animación es el proceso de eliminar el nodo raíz del árbol B:

imagen

Lo mismo es cierto para la inserción de un árbol B+, hay nodos redundantes y la inserción puede tener divisiones de nodos (si los nodos están saturados), pero como máximo solo está involucrada una ruta del árbol. Además, el árbol B+ se equilibrará automáticamente y no hay necesidad de algoritmos más complejos, como operaciones de rotación similares a los árboles rojo-negro.

Por lo tanto, la inserción y eliminación de árboles B+ son más eficientes .

3. Consulta de rango

El principio de la consulta equivalente de B-tree y B+-tree es básicamente el mismo. Primero, busque desde el nodo raíz, luego compare el rango de los datos de destino y finalmente ingrese el nodo secundario de forma recursiva para buscar.

Debido a que también hay una lista enlazada entre todos los nodos de hoja del árbol B+, este diseño es muy útil para la búsqueda de rangos . Por ejemplo, queremos saber el orden entre el 1 de diciembre y el 12 de diciembre. En este momento, podemos encontrar 12 primero El nodo de hoja donde se encuentra el mes 1, y luego use la lista enlazada para desplazarse hacia la derecha hasta que se encuentre el nodo del 12 de diciembre, de modo que no sea necesario consultar desde el nodo raíz, lo que ahorra aún más el tiempo requerido. para consulta

El árbol B no tiene una estructura en la que todos los nodos de hoja estén conectados en una lista vinculada, por lo que las consultas de rango solo se pueden completar a través del recorrido del árbol, lo que involucra operaciones de E/S de disco de múltiples nodos, y la eficiencia de la consulta de rango no es tan eficiente como el árbol B+.

Por lo tanto, hay una gran cantidad de escenarios de recuperación de rangos, que son adecuados para usar árboles B+, como bases de datos. Para una gran cantidad de escenarios de consulta de índice único, puede considerar árboles B, como MongoDB de nosql.

Árbol B+ en MySQL

El método de almacenamiento de MySQL varía según el motor de almacenamiento. El motor de almacenamiento más utilizado es el motor de almacenamiento Innodb, que utiliza el árbol B+ como estructura de datos de índice.

La siguiente figura es el árbol B+ en Innodb:

imagen

Pero el árbol B+ que utiliza Innodb tiene algunos puntos especiales, como:

  • Los nodos hoja del árbol B+ están conectados por una "lista doblemente enlazada", que tiene la ventaja de poder atravesar tanto a la derecha como a la izquierda.
  • El contenido del nodo de punto de árbol B+ es la página de datos. La página de datos almacena los registros del usuario y otra información. El tamaño predeterminado de cada página de datos es de 16 KB.

Innodb se divide en índices agrupados y secundarios según los diferentes tipos de índices. La diferencia entre ellos es que los nodos de hoja del índice agrupado almacenan los datos reales, todos los registros de usuario completos se almacenan en los nodos de hoja del índice agrupado y los nodos de hoja del índice secundario almacenan el valor de la clave principal, no el real. datos.

Debido a que los datos de la tabla se almacenan en los nodos de hoja del índice agrupado, el motor de almacenamiento de InnoDB debe crear un índice agrupado para la tabla, y debido a que los datos solo se almacenan físicamente en una copia, solo puede haber un índice agrupado, y Se pueden crear múltiples índices secundarios.

Para obtener más información sobre el árbol B+ de Innodb, consulte mi artículo anterior: Árbol B+ desde la perspectiva de la página de datos .

Resumir

MySQL conserva los datos en el disco duro, y el motor de almacenamiento de MySQL implementa la función de almacenamiento, por lo que discutir qué estructura de datos usa MySQL como índice es en realidad discutir qué estructura de datos se usa como índice para el almacenamiento. El motor es una estructura de datos que utiliza un árbol B+ como índice.

Para diseñar una estructura de datos de índice de MySQL, no solo tenga en cuenta la complejidad temporal de la adición, eliminación y modificación de la estructura de datos, sino que, lo que es más importante, tenga en cuenta el número de operaciones de E/S del disco. Debido a que los índices y los registros se almacenan en el disco duro, el disco duro es un dispositivo de almacenamiento muy lento. Cuando consultamos datos, es mejor completarlos en la menor cantidad posible de operaciones de E/S de disco.

Aunque el árbol de búsqueda binaria es una estructura binaria natural, puede hacer un buen uso de la búsqueda binaria para localizar datos rápidamente, pero tiene una situación extrema: siempre que el elemento insertado sea el elemento más grande en el árbol, conducirá a una búsqueda binaria. Degenere en una lista enlazada y la complejidad de la consulta se reducirá de O(logn) a O(n).

Para resolver el problema de que el árbol binario de búsqueda degenera en una lista enlazada, aparece un árbol binario autoequilibrado, que garantiza que la complejidad temporal de la operación de consulta siempre se mantendrá en O(logn). Pero es esencialmente un árbol binario, y cada nodo solo puede tener nodos secundarios 2. A medida que aumenta la cantidad de elementos, la altura del árbol será cada vez más alta.

La altura del árbol depende de la cantidad de operaciones de E/S del disco, porque el árbol se almacena en el disco y el acceso a cada nodo corresponde a una operación de E/S del disco, lo que significa que la altura del árbol es igual a cada uno. la hora en que se consultan los datos El número de operaciones de E/S de disco, por lo que cuanto mayor sea la altura del árbol, el rendimiento de la consulta se verá afectado.

Tanto B-tree como B+ utilizan un árbol de múltiples bifurcaciones para acortar la altura del árbol, por lo que estas dos estructuras de datos son muy adecuadas para recuperar datos almacenados en el disco.

Sin embargo, el motor de almacenamiento predeterminado de MySQL, InnoDB, utiliza B+ como estructura de datos indexados por las siguientes razones:

  • Los nodos que no son hojas del árbol B+ no almacenan los datos de registro reales, sino solo los índices. Por lo tanto, cuando la cantidad de datos es la misma, los nodos que no son hojas del árbol B+ pueden almacenar más índices que los nodos B- árbol que almacena tanto índices como registros. , por lo que el árbol B+ puede ser más "grueso" que el árbol B, y la cantidad de E/S de disco para consultar los nodos subyacentes será menor.
  • El árbol B+ tiene una gran cantidad de nodos redundantes (todos los nodos que no son hojas son índices redundantes). Estos índices redundantes hacen que el árbol B+ sea más eficiente en la inserción y eliminación. Por ejemplo, al eliminar el nodo raíz, no será como el Árbol B. Se producen cambios complejos en el árbol;
  • Los nodos secundarios del árbol B+ están conectados por una lista enlazada, lo que es beneficioso para la consulta de rango, y el árbol B debe realizar la consulta de rango, por lo que la consulta de rango solo se puede completar a través del recorrido del árbol, que involucran la operación de E/S de disco de múltiples nodos Las consultas de rango no son tan eficientes como los árboles B+.

¡sobre!

Supongo que te gusta

Origin blog.csdn.net/qq_34827674/article/details/123447620
Recomendado
Clasificación