Entrevistador de Dachang: ¿Cómo consultar rápidamente tablas con decenas de millones de datos?

Lectura recomendada:

Prefacio

  • Entrevistador: Hablemos de los diez millones de datos, ¿cómo los consulta?
  • Brother B: Consulta de paginación directa, use paginación de límite.
  • Entrevistador: ¿Lo ha practicado?
  • Hermano B: Debe haber

Presenta una canción "Cool and Cool" en este momento

Quizás algunas personas nunca se han encontrado con una tabla con decenas de millones de datos y no saben qué sucede cuando consultan decenas de millones de datos.

Hoy les mostraré los ejercicios prácticos, esta vez está basado en MySQL 5.7.26 para probar

Preparar datos

¿Qué pasa si no tienes 10 millones de datos?

Crear

10 millones de creación de códigos? Es imposible, es demasiado lento, realmente puede llevar un día. Puede utilizar scripts de base de datos para ejecutar mucho más rápido.

Crear mesa
CREATE TABLE `user_operation_log` (
  `id` int(11) NOT NULL AUTO_INCREMENT, 
  `user_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, 
  `ip` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, 
  `op_data` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, 
  `attr1` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, 
  `attr2` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, 
  `attr3` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, 
  `attr4` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, 
  `attr5` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, 
  `attr6` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, 
  `attr7` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, 
  `attr8` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, 
  `attr9` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, 
  `attr10` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, 
  `attr11` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, 
  `attr12` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, 
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; 
Crear script de datos

Al usar la inserción de lotes, la eficiencia será mucho más rápida y comprometer cada 1000 elementos, demasiados datos, también conducirá a una eficiencia de inserción de lotes lenta

DELIMITER ;
;
CREATE PROCEDURE batch_insert_log()BEGIN  DECLARE i iNT DEFAULT 1;
  DECLARE userId iNT DEFAULT 10000000;
 set @execSql = 'INSERT INTO `test`.`user_operation_log`(`user_id`, `ip`, `op_data`, `attr1`, `attr2`, `attr3`, `attr4`, `attr5`, `attr6`, `attr7`, `attr8`, `attr9`, `attr10`, `attr11`, `attr12`) VALUES';
 set @execData = '';
  WHILE i<=10000000 DO   set @attr = "'测试很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长的属性'";
  set @execData = concat(@execData, "(", userId + i, ", '10.0.69.175', '用户登录操作'", ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ",", @attr, ")");
  if i % 1000 = 0  then     set @stmtSql = concat(@execSql, @execData,";");
    prepare stmt from @stmtSql;
    execute stmt;
    DEALLOCATE prepare stmt;
    commit;
    set @execData = "";
    else     set @execData = concat(@execData, ",");
   end if;
  SET i=i+1;
  END WHILE;
END;
;
DELIMITER ;

empezar a probar

La configuración de la computadora de Brother es relativamente baja: el residuo de presión estándar win10 i5 lee y escribe aproximadamente 500 MB de SSD

Debido a la baja configuración, solo se prepararon 3148000 piezas de datos para esta prueba, que ocuparon 5G del disco (sin indexar). Después de ejecutar durante 38 minutos, los estudiantes con una buena configuración de computadora pueden insertar la prueba de datos multipunto.

SELECT count(1) FROM `user_operation_log`

Resultado devuelto: 3148000

Los tres tiempos de consulta son:

  • 14060 ms
  • 13755 ms
  • 13447 ms

Consulta de paginación normal

MySQL admite la declaración LIMIT para seleccionar el número especificado de datos, Oracle puede usar ROWNUM para seleccionar.

La sintaxis de la consulta de paginación de MySQL es la siguiente:

SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset
  • El primer parámetro especifica el desplazamiento de la primera fila de registro devuelta
  • El segundo parámetro especifica el número máximo de filas devueltas

Ahora comenzamos a probar los resultados de la consulta:

SELECT * FROM `user_operation_log` LIMIT 10000, 10

El tiempo para las 3 consultas es:

  • 59 ms
  • 49 ms
  • 50 ms

Parece que la velocidad está bien, pero es una base de datos local y la velocidad es naturalmente más rápida.

Prueba desde otro ángulo

Misma compensación, diferente volumen de datos
SELECT * FROM `user_operation_log` LIMIT 10000, 10
SELECT * FROM `user_operation_log` LIMIT 10000, 100
SELECT * FROM `user_operation_log` LIMIT 10000, 1000
SELECT * FROM `user_operation_log` LIMIT 10000, 10000
SELECT * FROM `user_operation_log` LIMIT 10000, 100000
SELECT * FROM `user_operation_log` LIMIT 10000, 1000000

El tiempo de consulta es el siguiente:

Cantidad la primera vez la segunda vez la tercera vez
10 piezas 53ms 52ms 47 ms
100 piezas 50 ms 60 ms 55ms
1000 piezas 61 ms 74ms 60 ms
10,000 164 ms 180 ms 217ms
100000 1609ms 1741ms 1764ms
1000000 16219ms 16889ms 17081ms

La conclusión se puede extraer de los resultados anteriores: cuanto mayor es la cantidad de datos, más tiempo lleva

Misma cantidad de datos, diferente compensación
SELECT * FROM `user_operation_log` LIMIT 100, 100
SELECT * FROM `user_operation_log` LIMIT 1000, 100
SELECT * FROM `user_operation_log` LIMIT 10000, 100
SELECT * FROM `user_operation_log` LIMIT 100000, 100
SELECT * FROM `user_operation_log` LIMIT 1000000, 100
Compensar la primera vez la segunda vez la tercera vez
100 36 ms 40 ms 36 ms
1000 31 ms 38 ms 32ms
10000 53ms 48 ms 51 ms
100000 622ms 576ms 627ms
1000000 4891ms 5076ms 4856ms

La conclusión se puede extraer de los resultados anteriores: cuanto mayor es el desplazamiento, más tiempo lleva

SELECT * FROM `user_operation_log` LIMIT 100, 100
SELECT id, attr FROM `user_operation_log` LIMIT 100, 100

Cómo optimizar

Ahora que hemos pasado por el lanzamiento anterior, también hemos llegado a la conclusión de que para los dos problemas anteriores: gran desplazamiento y gran cantidad de datos, procederemos a optimizar

Optimice el problema de la gran compensación

Usar subconsulta

Primero podemos ubicar la identificación de la posición de compensación y luego consultar los datos

SELECT  *  FROM  `user_operation_log`  LIMIT 1000000, 
 10SELECT id FROM  `user_operation_log`  LIMIT 1000000, 
 1SELECT  *  FROM  `user_operation_log`  WHERE id  >=  (
  SELECT id FROM  `user_operation_log`  LIMIT 1000000, 
   1
)  LIMIT 10 

Los resultados de la consulta son los siguientes:

sql Pasar el tiempo
Articulo 1 4818ms
Artículo 2 (sin índice) 4329ms
Artículo 2 (con índice) 199 ms
Artículo 3 (sin índice) 4319ms
Artículo 3 (con índice) 201 ms

Saque conclusiones de los resultados anteriores:

  • El primero toma más tiempo, el tercero es un poco mejor que el primero
  • Las subconsultas usan índices más rápido

Desventajas: solo se aplica cuando la identificación aumenta

En el caso de la identificación no creciente, puede utilizar la siguiente redacción, pero esta desventaja es que la consulta de paginación solo se puede colocar en la subconsulta

Nota: Algunas versiones de mysql no admiten el límite en la cláusula in, por lo que se utilizan múltiples selecciones anidadas

SELECT  *  FROM  `user_operation_log`  WHERE id IN (
  SELECT t.id FROM (
    SELECT id FROM  `user_operation_log`  LIMIT 1000000, 
     10
  )  AS t
) 
Adopte el método de restricción de identificación

Este método es más exigente, la identificación debe aumentar continuamente y el rango de identificación debe calcularse y luego usar entre, sql es el siguiente

SELECT * FROM `user_operation_log` WHERE id between 1000000 AND 1000100 LIMIT 100SELECT * FROM `user_operation_log` WHERE id >= 1000000 LIMIT 100

Los resultados de la consulta son los siguientes:

sql Pasar el tiempo
Articulo 1 22ms
Artículo 2 21ms

Se puede ver en los resultados que este método es muy rápido.

Nota: LIMIT aquí limita la cantidad de elementos y no usa compensación

Optimice el problema del gran volumen de datos

La cantidad de datos devueltos también afectará directamente la velocidad

SELECT * FROM `user_operation_log` LIMIT 1, 1000000

SELECT id FROM `user_operation_log` LIMIT 1, 1000000

SELECT id, user_id, ip, op_data, attr1, attr2, attr3, attr4, attr5, attr6, attr7, attr8, attr9, attr10, attr11, attr12 FROM `user_operation_log` LIMIT 1, 1000000

Los resultados de la consulta son los siguientes:

sql Pasar el tiempo
Articulo 1 15676ms
Artículo 2 7298ms
Artículo 3 15960ms

A partir de los resultados, se puede ver que al reducir las columnas innecesarias, la eficiencia de las consultas también se puede mejorar significativamente

La velocidad de consulta del primero y del tercero es casi la misma. En este momento, definitivamente se quejará, entonces, ¿qué estoy haciendo con tantos campos? Direct * no ha terminado

Tenga en cuenta que mi servidor y cliente MySQL están en la misma máquina , por lo que los datos de la consulta son similares. Los estudiantes con condiciones pueden probar el cliente y MySQL por separado

SELECCIONAR * ¿No es fragante?

Por cierto, agregue aquí por qué SELECT * debería estar prohibido. ¿No es simple y estúpido, no es fragante?

Dos puntos principales:

  1. Con "SELECT *" la base de datos necesita analizar más objetos, campos, permisos, atributos y otro contenido relacionado. En el caso de sentencias SQL complejas y un análisis más duro, causará una gran carga en la base de datos.
  2. Aumente la sobrecarga de la red, * A veces, los campos de texto grandes e inútiles como log e IconMD5 se traen por error, y el tamaño de la transmisión de datos aumentará geométricamente. Especialmente MySQL y la aplicación no están en la misma máquina, esta sobrecarga es muy obvia.

Final

Finalmente, espero que todos puedan hacerlo por su cuenta. Definitivamente puedes ganar más. ¡Bienvenido a dejar un mensaje! !

Acabo de crear el guión para ti, ¡qué estás esperando! ! !

Supongo que te gusta

Origin blog.csdn.net/weixin_45784983/article/details/108295166
Recomendado
Clasificación