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:
- 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.
- 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! ! !