2016-07-14 12 views
1

Ich habe eine erste Tabelle mit meiner ips als Integer (500k Zeilen) gespeichert, und eine zweite mit Bereichen von schwarz aufgeführten ips und der Grund der schwarzen Auflistung (10M Zeilen) hier ist die Tabellenstruktur:MARIADB: Index nicht für eine Auswahl mit Join in einem Bereich verwendet

CREATE TABLE `black_lists` (
    `id` INT(11) NOT NULL AUTO_INCREMENT, 
    `ip_start` INT(11) UNSIGNED NOT NULL, 
    `ip_end` INT(11) UNSIGNED NULL DEFAULT NULL, 
    `reason` VARCHAR(3) NOT NULL, 
    `excluded` TINYINT(1) NULL DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    INDEX `ip_range` (`ip_end`, `ip_start`), 
    INDEX `ip_start` (`ip_start`), 
    INDEX `ip_end` (`ip_end`), 
) 
COLLATE='latin1_swedish_ci' 
ENGINE=InnoDB 
AUTO_INCREMENT=10747741 
; 

CREATE TABLE `ips` (
    `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT 'Id ips', 
    `idhost` INT(11) NOT NULL COMMENT 'Id Host', 
    `ip` VARCHAR(45) NULL DEFAULT NULL COMMENT 'Ip', 
    `ipint` INT(11) UNSIGNED NULL DEFAULT NULL COMMENT 'Int ip', 
    `type` VARCHAR(45) NULL DEFAULT NULL COMMENT 'Type', 
    PRIMARY KEY (`id`), 
    INDEX `host` (`idhost`), 
    INDEX `index3` (`ip`), 
    INDEX `index4` (`idhost`, `ip`), 
    INDEX `ipsin` (`ipint`) 
) 
COLLATE='latin1_swedish_ci' 
ENGINE=InnoDB 
AUTO_INCREMENT=675651; 

mein Problem ist, wenn ich versuche, diese Abfrage kein Index verwendet wird, laufen und es eine Ewigkeit bis Ende nimmt:

select i.ip,s1.reason 
from ips i 
    left join black_lists s1 on i.ipint BETWEEN s1.ip_start and s1.ip_end; 

ich verwende MariaDB 10.0.16

+1

Wenn Sie eine Abfrage geschrieben haben, die mindestens * einige * aktuelle Informationen enthält, wo Sie mit dem Durchsuchen von Daten beginnen können, dann werden Indizes verwendet. Warum verbringst du keine 20 Sekunden damit, darüber nachzudenken, was du getan hast, bevor du eine Frage wie diese gestellt hast? Wissen Sie auch, welcher Index wirklich ist? Es ist keine schwarze Magie, die Anfragen schnell aus heiterem Himmel macht. Ich schlage vor, dass Sie einige Informationen über die Indizes und ihre Funktionsweise finden, bevor Sie Hilfe bei einer Abfrage anfordern, die keine Indizes verwenden kann, selbst wenn Sie von einer Fee einen Wunsch erhalten haben - sie konnte diese Abfrage nicht verwenden Indizes. –

+0

Ich habe diese Frage gestellt, weil diese Abfrage Indizes verwendet: "select s1.reason von black_lists s1 auf 111111111 BETWEEN s1.ip_start und s1.ip_end; ", also nahm ich an, wenn ich eine Linke beitreten würde, wäre es wie eine Schleife bei dieser –

+0

Aber Sie haben hier einen ** Wert ** angegeben, damit MySQL weiß, wo Sie anfangen sollten. Wenn Sie keinen tatsächlichen Wert angeben (Nummer wie 111111111) Was kann es dann tun, außer alles anzuschauen und eine riesige Menge an Platten auszuspucken? –

Antwort

2

Wahr.

Der Optimierer hat keine Kenntnis davon, dass die Werte von start..end nicht überlappend sind und auch nichts anderes offensichtlich ist. So kann das am besten, es tun, ist entscheiden zwischen

s1.ip_start <= i.ipint -- and use INDEX(ip_start), or 
s1.ip_end >= i.ipint -- and use INDEX(ip_end) 

Entweder der in nach oben von der Hälfte der Tabelle abgetastet wird, führen könnte.

In 2 Schritten konnten Sie das gewünschte Ziel für eine IP erreichen; sagen wir mal @ip:

SELECT ip_start, reason 
    FROM black_lists 
    WHERE ip_start <= @ip 
    ORDER BY ip_start DESC 
    LIMIT 1 

Aber danach, müssen Sie sehen, ob die ip_end zu diesem ip_start entsprechenden < ist = @ip vor der Entscheidung, ob Sie eine schwarze Liste Artikel haben.

SELECT reason 
    FROM (...) a -- fill in the above query 
    JOIN black_lists b USING(ip_start) 
    WHERE b.ip_end <= @ip 

Das wird entweder die reason oder keine Zeilen zurückgeben.

Trotz der Komplexität wird es sehr schnell sein. Aber Sie scheinen eine Reihe von IPs zu überprüfen. Das macht es komplexer.

Für black_lists scheint id nicht erforderlich zu sein. Schlagen Sie die 4-Indizes mit nur 2 ersetzen:

PRIMARY KEY(ip_start, ip_end), 
INDEX(ip_end) 

In ips ist nicht ip einzigartig? Wenn ja, loszuwerden, wenn id und ändern 5 Indizes 3:

PRIMARY KEY(idint), 
INDEX(host, ip), 
INDEX(ip) 

Sie erlaubt haben, mehr als genug in den VARCHAR für IPv6, aber nicht in INT UNSIGNED.

More discussion.