B + explicación del árbol

Prólogo

Cada vez que ejecutamos un determinado SQL y lo encontramos lento, responderemos inconscientemente si se agrega el índice, por lo que alguna vez ha pensado por qué se agrega el índice para que la búsqueda de datos sea más rápida, y la estructura subyacente del índice generalmente se almacena Sí, creo que todos tienen la respuesta después de leer el título, ¡sí! B + árbol! Entonces, ¿en qué se diferencia de la lista vinculada general, el hash, etc. ¿Por qué la mayoría de los motores de almacenamiento eligen usarlo? Hoy desacreditaré el árbol B +. Creo que después de leer este artículo, el árbol B + ya no es misterioso para ti. ¡Comprender las siguientes preguntas de entrevista de alta frecuencia será de gran ayuda!

  • Por qué el índice usa comúnmente el árbol B + como la estructura de datos subyacente

  • Además del índice de árbol B +, ¿qué índice conoces?

  • ¿Por qué recomendar la identificación de autoincremento como clave principal?

  • ¿Qué es la división de página, la fusión de página?

  • Cómo encontrar registros de filas según el índice

Este artículo explicará el árbol B + de los siguientes aspectos

  1. Problema de definición

  2. Comparación de varias estructuras de datos comunes.

  3. División de página y fusión de página

Problema de definición

Para saber por qué la capa inferior del índice usa el árbol B +, depende del problema que resuelva. Podemos pensar en qué más SQL usamos diariamente.

Supongamos que tenemos la siguiente tabla de usuario:

CREATE  TABLE  `user` (
  `id` int(11) unsigned  NOT  NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT  NULL COMMENT '姓名',
  `idcard` varchar(20) DEFAULT  NULL COMMENT '身份证号码',
  `age` tinyint(10) DEFAULT  NULL  COMMENT '年龄',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT  CHARSET=utf8 COMMENT='用户信息';

Generalmente tendremos los siguientes requisitos:

1. Verifique la información del usuario basada en la identificación del usuario

select * from  user  where  id = 123;

2. Encuentre información del usuario basada en valores de intervalo

select * from  user  where  id > 123  and  id < 234;

3. Organice en orden inverso por ID y recupere la información del usuario en páginas

select * from  user  where  id <  1234  order  by  id  desc  limit  10;

Del SQL común anterior, podemos ver que la estructura de datos utilizada por el índice debe cumplir las siguientes tres condiciones

  1. Búsqueda precisa y rápida basada en cierto valor

  2. Encuentre rápidamente datos en este intervalo en función de los límites superior e inferior del valor del intervalo

  3. Los valores de índice deben ordenarse y son compatibles con la búsqueda de orden rápida y la búsqueda de orden inverso

A continuación, tomamos el índice de clave primaria (índice de identificación) como ejemplo para ver cómo construirlo con la estructura de datos correspondiente

Comparación de varias estructuras de datos comunes.

A continuación, pensamos qué estructuras de datos cumplen las condiciones anteriores.

1. Tabla hash

Una tabla hash (también llamada tabla hash) es una estructura de datos a la que se accede directamente en función de un valor clave (valor clave). Permite asignar el valor del código a la posición correspondiente de la tabla hash mediante la conversión de la función hash, y la eficiencia de búsqueda es muy alta. El índice hash se implementa en función de la tabla hash. Suponiendo que hayamos establecido un índice hash en el nombre, el proceso de búsqueda se muestra en la siguiente figura:

Para cada fila de datos, el motor de almacenamiento calculará un código hash (la posición de la tabla hash en la figura anterior) para todas las columnas de índice (columna de nombre en la figura anterior), y cada elemento en la tabla hash apunta al puntero de la fila de datos. Solo almacena el valor hash correspondiente, por lo que la estructura del índice es muy compacta, lo que hace que la velocidad de búsqueda del índice hash sea muy rápida. Pero el índice hash también tiene sus desventajas, como sigue:

  1. Para el índice hash, solo es válida la consulta que coincida exactamente con todas las columnas del índice. Por ejemplo, establecí un índice hash en la columna (A, B). Si solo se consulta la columna de datos A, no se puede usar el índice.

  2. Los índices de hash no se almacenan en orden de acuerdo con el valor del índice, por lo que no se pueden usar para ordenar, es decir, no se pueden buscar rápidamente de acuerdo con el intervalo

  3. Los índices hash solo contienen valores hash y punteros de fila, y no almacenan valores de campo, por lo que no puede usar los valores en el índice para evitar leer filas. Sin embargo, debido a que la mayoría del índice hash se realiza en la memoria, en la mayoría de los casos este es el caso. No es un problema

  4. Los índices hash solo admiten consultas de comparación equivalentes, que incluyen =, IN (), y no admiten ningún rango de búsqueda, como edad> 17

En resumen, el índice hash solo es adecuado para ocasiones específicas. Si se usa correctamente, realmente puede aportar una gran mejora en el rendimiento. Por ejemplo, en el motor InnoDB, hay una función especial llamada "índice hash adaptativo". Si InnoDB nota que ciertos valores de columna de índice se usan con frecuencia, creará un índice hash basado en el índice del árbol B + en la memoria, de modo que el árbol B + también tenga las ventajas del índice hash, como el hash rápido Encuentra

2. Lista vinculada

La lista doblemente vinculada admite búsqueda secuencial y búsqueda de orden inverso, como se muestra a continuación

Pero obviamente no es compatible con lo que dijimos para buscar rápidamente por un cierto valor o intervalo . Además, sabemos que los datos en la tabla aumentan constantemente, y el índice debe insertarse y actualizarse a tiempo. La lista vinculada obviamente no admite la inserción rápida de datos, por lo que puede Ya sea para transformar sobre la base de la lista vinculada, deje que admita búsqueda rápida, actualización, eliminación. Hay una estructura que satisface nuestras necesidades, y aquí presentamos el concepto de una mesa de salto.

¿Qué es una tabla de salto? En pocas palabras, se forma una tabla de salto agregando múltiples capas de índices en la parte superior de la lista vinculada. Como se muestra a continuación

Supongamos que ahora queremos buscar registros en el intervalo 7-13, ya no tenemos que buscar desde el principio, siempre que comencemos a buscar en el índice secundario en la figura anterior, podemos encontrar la posición del intervalo de la lista vinculada después de recorrer tres veces, la complejidad temporal es O ( logn), muy rápido, de esta manera, la tabla de salto puede satisfacer nuestras necesidades. De hecho, su estructura está muy cerca del árbol B +, pero el árbol B + se desarrolla a partir del árbol de búsqueda binario equilibrado. A continuación, veremos paso a paso cómo transformar el árbol de búsqueda binaria equilibrado en un árbol B +.

Primero mire lo que es un árbol de búsqueda binaria balanceada El árbol de búsqueda binaria balanceada tiene las siguientes propiedades:

  1. Si el subárbol izquierdo no está vacío, los valores de todos los nodos en el subárbol izquierdo son menores que el valor de su nodo raíz;

  2. Si el subárbol derecho no está vacío, los valores de todos los nodos en el subárbol derecho son mayores o iguales que el valor de su nodo raíz;

  3. El valor absoluto (factor de equilibrio) de la diferencia de altura entre los subárboles izquierdo y derecho de cada nodo no hoja es como máximo 1.

La siguiente figura es un árbol de búsqueda binario balanceado.

Por sus características, podemos ver que la complejidad temporal de encontrar nodos en un árbol de búsqueda binario balanceado es O (log2n)

Ahora lo transformamos en un árbol B +

Se puede ver que la principal diferencia es que todos los valores de los nodos están conectados en el último nodo hoja con una lista doblemente enlazada. Compárelo cuidadosamente con la tabla de salto. ¿Es muy similar? Ahora si queremos encontrar el número en este intervalo 15 ~ 27 Encuentre el nodo 15 (complejidad de tiempo logn = 3 veces) y luego atraviese desde el frente al nodo 27, puede encontrar el nodo en este intervalo, de modo que admita perfectamente las tres necesidades que mencionamos: encuentre el valor rápidamente, Intervalo, búsqueda de orden inverso.

Supongamos que hay 100 millones de nodos, cuántas veces debe consultar cada nodo, obviamente el máximo es log2.1 mil millones = 27 veces, si estos 100 millones de nodos están en la memoria, entonces 27 veces obviamente no es un problema, se puede decir que es muy rápido, Pero surge un nuevo problema: ¿cuál es el tamaño de estos 100 millones de nodos en la memoria? Vamos a calcularlo brevemente. Suponiendo 16 bytes por nodo, ¡100 millones de nodos probablemente ocuparán 1.5G de memoria! Para un recurso tan valioso como la memoria, es un consumo de espacio terrible. Esto es solo un índice. En general, definiremos múltiples índices en la tabla o múltiples tablas en la biblioteca. ¡En este caso, la memoria pronto estará llena! Entonces, obviamente, es un problema cargar completamente un índice de árbol B + en la memoria, cómo resolverlo.

No podemos ponerlo en el disco. El espacio en el disco es más que la memoria, pero el nuevo problema es nuevamente. Sabemos que la velocidad de lectura de la memoria y el disco es muy diferente. Por lo general, la memoria es del orden de nanosegundos. El disco tiene milisegundos y, al leer el mismo tamaño de datos, la diferencia entre los dos puede ser decenas de miles de veces, por lo que las 27 consultas que calculamos en el paso anterior son muy terribles si se colocan en el disco (buscar un nodo puede considerarse como una sola vez) Disco IO, es decir, hay 27 discos IO!), ¿Se pueden optimizar 27 consultas?

Se puede observar claramente que el número de consultas está relacionado con la altura del árbol y con qué está relacionada la altura del árbol. Obviamente está relacionado con el número de nodos secundarios de cada nodo, es decir, N en el árbol de la horquilla N. Suponiendo que ahora hay 16 números, tenemos Use un árbol binario y un árbol de cinco árboles para construir, y vea cuál es la altura del árbol

Se puede ver que si usa un árbol binario, necesita atravesar 5 nodos. Si usa un árbol de cinco, solo necesita atravesar 3 veces, y el disco IO se reduce dos veces. Mirando hacia atrás a los 100 millones de nodos anteriores, si usamos un árbol de 100 Para construir, ¿cuántas IO se necesitan?

Se puede ver que atraviesa hasta cinco veces (de hecho, el nodo raíz generalmente se almacena en la memoria, por lo que puede considerarse como 4 veces). ¡Disk IO se ha reducido de 27 a 5! Se puede decir que el rendimiento ha mejorado mucho. Algunas personas dicen que 5 veces es demasiado. ¿Es posible cambiar el árbol de 100 horquillas a 1000 o 10000, para que el número de IO pueda reducirse aún más sin el número de IO?

Aquí tenemos que entender el concepto de páginas (página), y en el ordenador, ya sea de memoria o disco, el sistema operativo estamos leyendo el tamaño de página (tamaño de la página es por lo general de 4 kb), el disco va a leer cada una pre Leer , leerá los datos continuos en la memoria por adelantado, para evitar múltiples E / S, este es el famoso principio de localidad en la computadora , es decir, utilizo un dato, es probable que los datos cercanos a este dato también Usado, simplemente cargado juntos, guardando múltiples IOs para reducir la velocidad. ¿Qué tan grandes son estos datos continuos? Debe ser un múltiplo entero del tamaño de página del sistema operativo, estos datos continuos son la página MySQL, el valor predeterminado es 16 KB, lo que significa que para Los nodos del árbol B + se configuran preferiblemente en el tamaño de página (16 KB), de modo que un nodo en el árbol B + solo tendrá una lectura IO.

Algunas personas preguntarán si este tamaño de página es mayor: cuanto mayor sea la configuración, más datos podrá contener el nodo. Cuanto menor sea la altura del árbol, menor será el IO. Aquí debemos prestar atención al tamaño de la página. No más grande es mejor, InnoDB administra los datos de la página leídos del disco a través del búfer de la agrupación en la memoria. Si la página es demasiado grande, la agrupación de almacenamiento intermedio se llenará rápidamente, lo que puede hacer que las páginas se intercambien con frecuencia entre la memoria y el disco, lo que afecta el rendimiento.

A través del análisis anterior, creo que no es difícil adivinar cómo establecer el N en el árbol de la bifurcación de N, siempre que se seleccione el tamaño de cada nodo para garantizar que el tamaño de cada nodo sea igual al tamaño de una página (16kb).

 

División de página y fusión de página

Ahora echemos un vistazo a la pregunta al principio. ¿Por qué recomienda la identificación de auto-incremento como clave primaria? ¿No es posible construir una clave primaria? Algunas personas pueden decir que la ID del usuario es única y puede usarse como clave primaria. Suponiendo que la ID es la clave primaria ¿Cuál será el problema?

Para mantener el orden del índice, el árbol B + actualiza el índice cada vez que se inserta o actualiza un registro. Suponga que el árbol B + original basado en la tarjeta de identificación es el siguiente (suponiendo que un árbol binario, solo los primeros cuatro dígitos de la tarjeta de identificación se enumeran en la figura)

Ahora hay un registro correspondiente a la tarjeta de identificación que comienza con 3604 insertado en db. En este momento, el índice debe actualizarse. Si se actualiza ordenando, obviamente el número de identificación de este 3604 debe insertarse después del nodo izquierdo 3504 (como se muestra en la figura siguiente, suponiendo un árbol binario)

Si el número de identificación 3604 se inserta después de 3504, el número de elementos en este nodo será 3, lo que obviamente no cumple con las condiciones del árbol binario, lo que provocará la división de la página . Debe ajustar este nodo para que se ajuste al árbol binario. Condición

Como se muestra en la figura: después del ajuste, se cumplen las condiciones del árbol binario

Este ajuste debido a la división de la página conducirá inevitablemente a una disminución en el rendimiento, especialmente si la tarjeta de identificación se usa como clave principal, debido a la aleatoriedad de la tarjeta de identificación, inevitablemente causará una gran cantidad de inserciones de nodo aleatorio, lo que provocará una gran cantidad de divisiones de página, lo que El rendimiento se reduce drásticamente. Si la identificación de aumento automático se utiliza como clave principal, la identificación generada en la tabla recién insertada es mayor que todos los valores en el índice, por lo que debe combinarse con el nodo existente (el número de elementos no está lleno) , O colóquelo en el nodo recién creado (como se muestra a continuación), de modo que si la identificación de auto-incremento se usa como la clave principal, no hay problema de división de página. ¡Se recomienda!

Si hay una división de página, debe haber una fusión de página. ¿Cuándo se producirá la fusión de página? Cuando se elimina el registro de la tabla, también se debe eliminar el índice. En este momento, puede ocurrir fusión de página, como se muestra en la figura

Cuando eliminemos la fila correspondiente a la identificación 7, 9, el índice en la figura anterior se actualizará y se eliminará 7, 9. En este momento, 8, 10 se deben combinar en un nodo, de lo contrario 8, 10 se dispersarán en dos nodos En lo anterior, puede causar dos lecturas de E / S, lo que inevitablemente afectará la eficiencia de búsqueda. Luego, cuando ocurra la fusión de páginas, podemos establecer un umbral, por ejemplo, para N árboles de bifurcación, cuando el número de nodos es menor que N / 2 Debe fusionarse con los nodos cercanos, pero debe tenerse en cuenta que el tamaño de los elementos en el nodo fusionado puede exceder N, causando la división de la página, y el nodo padre debe ajustarse para satisfacer el árbol de la bifurcación N.

Cómo encontrar registros de filas según el índice

Creo que todos deberían tener dudas después de leer la introducción del índice de árbol B + anterior. Cómo encontrar el registro de fila de acuerdo con el valor de índice correspondiente, de hecho, el registro de fila correspondiente se coloca en el último nodo de hoja, y se encuentra el valor de índice, y se encuentra Registro de línea. Como se muestra

Se puede ver que los nodos no hoja solo almacenan el valor del índice, y solo almacenan el registro de la fila en la última fila, lo que reduce en gran medida el tamaño del índice, y siempre que se encuentre el valor del índice, se encuentra el registro de la fila, lo que también mejora la eficiencia.

Este tipo de índice que almacena una fila completa de registros en un nodo hoja se denomina índice agrupado, y otros se denominan índices no agrupados.

Resumen del árbol B +

En resumen, el árbol B + tiene las siguientes características:

  • El número de nodos secundarios en cada nodo no puede exceder N, ni ser menor que N / 2 (de lo contrario, provocará división o fusión de página)

  • El número de nodos secundarios del nodo raíz no puede exceder m / 2, esta es una excepción

  • m El árbol de la horquilla solo almacena el índice, y en realidad no almacena los datos, solo el nodo hoja de la última fila almacena los datos de la fila.

  • Los nodos hoja están conectados en serie a través de una lista vinculada, por lo que es conveniente buscar por intervalo

Resumen

Este artículo resume las características del árbol B + del SQL común en la vida diaria. Creo que todos deberían tener una comprensión más clara del índice del árbol B +, entonces, ¿por qué tenemos que dominar el original subyacente, después de aprender el árbol B +, mire el principio Las pocas preguntas que planteé son en realidad las mismas: cavar más profundo en la capa inferior a veces te permite cambiar constantemente.

 

117 artículos originales publicados · 69 alabanzas · 10,000+ vistas

Supongo que te gusta

Origin blog.csdn.net/zsd0819qwq/article/details/105339619
Recomendado
Clasificación