Wenn ich meiner Abfrage "deutlich" hinzufüge, erhöht sich die Abfragezeit von 0,015 auf über 6 Sekunden.
Ich möchte mehrere Tabellen verbinden, die über Fremdschlüssel verknüpft sind, und eine bestimmte Spalte daraus erhalten:
select distinct table3.idtable3 from
table1
join table2 on table1.idtable1 = table2.fkey
join table3 on table2.idtable2 = table3.fkey
where table1.idtable1 = 1
Die eindeutige Abfrage dauert 6 Sekunden, was mir verbesserungsfähig erscheint.
Mit Auswahl:
Dauer: 0,015 s / Abruf: 5,532 s (5,760,434 Zeilen)
Erklären:
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
Mit eindeutiger Auswahl:
Dauer: 6.625s / Abruf: 0.000s (1000 Zeilen)
Erklären:
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
Datenbank: Datenbank-Snippet
Code zum Testen / 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()
Antworten:
Danke für das
CREATE TABLEs
; Ohne sie hätten Sie vielleicht nie eine Antwort bekommen.PRIMARY KEY
. Wenn Sie eine Spalte (oder eine Kombination von Spalten) haben, die "natürlich" funktioniert, verwenden Sie diese. Andernfalls verwenden Sie eineAUTO_INCREMENT
.INDEX(fkey)
wirdINVISIBLE
daher nicht verwendet. Verschwenden Sie keine Lernzeit mitVISIBLE
/INVISIBLE
, Sie werden sie möglicherweise nie in Ihrer Karriere brauchen.Und...
Beachten Sie, wie beide ungefähr 6 Sekunden sind. Es ist nur so, dass die Zeit anders aufgeteilt ist.
DISTINCT
kann die Abfrage die Daten sofort auspumpen, dauert jedoch aufgrund der Netzwerklatenz lange.DISTINCT
kann die erste Zeile erst nach dem Vorformen der "Deduplizierung" herauskommen, die wahrscheinlich eine "temporäre" (siehe dieEXPLAIN
) und eine Sortierung beinhaltet. Jetzt ist die ganze Zeit mit dem Rechnen beschäftigt, bevor die Daten gesendet werden.DISTINCT
ist etwas langsamer (Gesamtzeit), da zusätzliche Schritte zum Sammeln und Sortieren von 5,7 Millionen Zeilen erforderlich sind.quelle
DISTINCT
ist sortiert, manchmal nicht.SELECT SQL_NO_CACHE ...
.