Cuando agrego 'distintivo' a mi consulta, el tiempo de consulta aumenta de 0.015 a más de 6 segundos.
Quiero unir varias tablas, que están vinculadas a través de claves externas y obtener una columna distinta de ella:
select distinct table3.idtable3 from
table1
join table2 on table1.idtable1 = table2.fkey
join table3 on table2.idtable2 = table3.fkey
where table1.idtable1 = 1
La consulta distinta lleva 6 segundos, lo que me parece mejorable.
Con seleccionar:
duración: 0.015s / búsqueda: 5.532s (5.760.434 filas)
Explique:
id, select_type, table, partitions, type, possible_keys, key, key_len, ref, rows, filtered, Extra
1 SIMPLE table1 index asd asd 137 10 10.00 Using where; Using index
1 SIMPLE table2 ALL idtable2 200 25.00 Using where; Using join buffer (Block Nested Loop)
1 SIMPLE table3 ref fkey_table2_table_3_idx fkey_table2_table_3_idx 138 mydb.table2.idtable2 66641 100.00
Con selección distinta:
duración: 6.625s / búsqueda: 0.000s (1000 filas)
Explique:
id, select_type, table, partitions, type, possible_keys, key, key_len, ref, rows, filtered, Extra
1 SIMPLE table1 index asd asd 137 10 10.00 Using where; Using index; Using temporary
1 SIMPLE table2 ALL idtable2 200 25.00 Using where; Using join buffer (Block Nested Loop)
1 SIMPLE table3 ref fkey_table2_table_3_idx fkey_table2_table_3_idx 138 mydb.table2.idtable2 66641 100.00
Base de datos: fragmento de base de datos
Código para pruebas / MCRE:
import mysql.connector
import time
import numpy as np
"""
-- MySQL Script generated by MySQL Workbench
-- Fri Jan 17 12:19:26 2020
-- Model: New Model Version: 1.0
-- MySQL Workbench Forward Engineering
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
-- -----------------------------------------------------
-- Schema mydb
-- -----------------------------------------------------
-- -----------------------------------------------------
-- Schema mydb
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET utf8 ;
USE `mydb` ;
-- -----------------------------------------------------
-- Table `mydb`.`table1`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`table1` (
`idtable1` VARCHAR(45) NOT NULL,
INDEX `asd` (`idtable1` ASC) VISIBLE)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`table2`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`table2` (
`idtable2` VARCHAR(45) NOT NULL,
`fkey` VARCHAR(45) NULL,
INDEX `link_table1_table2_idx` (`fkey` ASC) INVISIBLE,
INDEX `idtable2` (`idtable2` ASC) VISIBLE,
CONSTRAINT `link_table1_table2`
FOREIGN KEY (`fkey`)
REFERENCES `mydb`.`table1` (`idtable1`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`table3`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`table3` (
`idtable3` VARCHAR(45) NOT NULL,
`fkey` VARCHAR(45) NULL,
INDEX `fkey_table2_table_3_idx` (`fkey` ASC) VISIBLE,
CONSTRAINT `fkey_table2_table_3`
FOREIGN KEY (`fkey`)
REFERENCES `mydb`.`table2` (`idtable2`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
"""
def insertData():
for i in range(2):
num_distinct_table1_values = 5
num_distinct_table2_values = 10
num_distinct_table3_values = 1000
num_entries_table1 = int(num_distinct_table1_values)
num_entries_table2 = int(num_distinct_table2_values * 10)
num_entries_table3 = int(num_distinct_table3_values * 300)
random_numbers_table1_id = range(num_distinct_table1_values)
random_numbers_table2_id = np.random.randint(num_distinct_table2_values, size=int(num_entries_table2))
random_numbers_table2_fkey = np.random.randint(num_distinct_table1_values, size=int(num_entries_table2))
random_numbers_table3_id = np.random.randint(num_distinct_table3_values, size=int(num_entries_table3))
random_numbers_table3_fkey = np.random.randint(num_distinct_table2_values, size=int(num_entries_table3))
value_string_table1 = ','.join([f"('{i_name}')" for i_name in random_numbers_table1_id])
value_string_table2=""
for i in range(num_entries_table2):
value_string_table2 = value_string_table2+','.join(
["('{id}','{fkey}'),".format(id=random_numbers_table2_id[i], fkey=random_numbers_table2_fkey[i])])
value_string_table3=""
for i in range(num_entries_table3):
value_string_table3 = value_string_table3+','.join(
["('{id}','{fkey}'),".format(id=random_numbers_table3_id[i], fkey=random_numbers_table3_fkey[i])])
# fill table 1
mySql_insert_query = f"INSERT INTO table1 (idtable1) VALUES {value_string_table1}"
cursor.execute(mySql_insert_query)
conn.commit()
print("Done table 1")
# fill table 2
mySql_insert_query = f"INSERT INTO table2 (idtable2, fkey) VALUES {value_string_table2}"
mySql_insert_query=mySql_insert_query[0:-1]
cursor.execute(mySql_insert_query)
print("Done table 2")
# fill table 3
mySql_insert_query = f"INSERT INTO table3 (idtable3, fkey) VALUES {value_string_table3}"
mySql_insert_query = mySql_insert_query[0:- 1]
cursor.execute(mySql_insert_query)
print("Done table 3")
conn.commit()
conn = mysql.connector.connect(user='root', password='admin', host='127.0.0.1',
database='mydb', raise_on_warnings=True, autocommit=False)
cursor = conn.cursor()
insertData()
conn.close()
Respuestas:
Gracias por el
CREATE TABLEs
; Es posible que nunca haya recibido una respuesta sin ellos.PRIMARY KEY
. Si tiene una columna (o combinación de columnas) que funciona "naturalmente", úsela. De lo contrario, use unAUTO_INCREMENT
.INDEX(fkey)
esINVISIBLE
, por lo tanto, no se utiliza. No pierdas el tiempo de aprendizaje enVISIBLE
/INVISIBLE
, es posible que nunca los necesites en tu carrera.Y...
Observe cómo ambos son unos 6 segundos. Es solo que el tiempo se divide de manera diferente.
DISTINCT
, la consulta puede bombear los datos inmediatamente, pero lleva mucho tiempo debido a la latencia de la red.DISTINCT
, la primera fila no puede salir hasta después de preformar la "desduplicación", que probablemente implica un "temporal" (ver elEXPLAIN
) y una ordenación. Entonces, ahora todo el tiempo está involucrado en la computación antes de enviar los datos.DISTINCT
uno es un poco más lento (tiempo total) debido al paso adicional de recopilar y ordenar 5.7M filas.fuente
DISTINCT
se ordena, a veces no.SELECT SQL_NO_CACHE ...
.