2016-06-09 29 views
0

Ich habe eine Tabelle mit etwa 13 Millionen Zeilen und mein Primärschlüssel ist ein hexadezimaler Wert VARBINARY(16).MySQL/MariaDB Reihen nach Punkten sortieren

Ich verwende die Folge Abfrage meine Ergebnisse zu erhalten:

SELECT * 
FROM dbip 
WHERE ip_start <= INET6_ATON('XXX.XX.XX.XX') 
    AND addr_type = 4 
ORDER BY ip_start DESC 
LIMIT 1; 

Aber diese Abfrage etwa 0,1 Sekunden dauern, und es sollte etwa 0,02 Sekunden oder weniger betragen.

99% meiner Bandbreite ist in Brasilien, die nur 131.270 Zeilen ist, habe ich die Spalte country in meiner Datenbank. Also, was kann ich tun, um diese IP zuerst in Brasilien zu suchen, nachdem im Rest der Tabelle? Denkst du, auf diese Weise werde ich einige Millisekunden gewinnen?

Meine Tabelle:

CREATE TABLE `dbip` 
(
    `addr_type` TINYINT(1) NOT NULL, 
    `ip_start` VARBINARY(16) NOT NULL, 
    `ip_end` VARBINARY(16) NOT NULL, 
    `country` CHAR(2) NOT NULL, 
    `stateprov` VARCHAR(80) NOT NULL, 
    `city` VARCHAR(80) NOT NULL, 
    `latitude` FLOAT NOT NULL, 
    `longitude` FLOAT NOT NULL, 
    `timezone_offset` FLOAT NOT NULL, 
    `timezone_name` VARCHAR(64) NOT NULL, 
    `isp_name` VARCHAR(128) NOT NULL, 
    `connection_type` VARCHAR(8) NULL DEFAULT NULL, 
    `organization_name` VARCHAR(128) NOT NULL, 
    PRIMARY KEY (`ip_start`) 
) 
COLLATE='utf8_general_ci' 
ENGINE=InnoDB 
; 

Dies ist ein Echtzeit-Daten, so dass es schnell sein muss. Ich auch Vorschläge akzeptieren meine Datenbank zu ändern, habe ich versucht, einige mit in Speicher, aber es nicht akzeptieren, binäre Werte als Index oder sie mir nicht erlauben <= Befehl gießen Dieses

+0

Was ist Ihr Tabellenschema !? – Alex

+0

Wie haben Sie festgestellt, dass Ihre Abfragezeit "0,02 Sekunden oder weniger" betragen sollte? –

+0

@BobJarvis - System-Mindestanforderung. Ich brauche das, um eine bessere Leistung als möglich – Guhh

Antwort

0

verwenden ziemlich Schema und Optimierung benötigen.

Zuerst müssen Sie alles INDEX, was für sofortige Bezugnahme und auch Gruppierung als machbar erachtet. Index der Ländercode selbst die Auswahlzeit abgeholzt wird, das heißt

SELECT * FROM dbip 
    WHERE 
    country="BR" 
    AND addr_type = 4 
    AND ip_start <= INET6_ATON('XXX.XX.XX.') 
    ORDER BY ip_start DESC; 

die wählen zu 131.270 Reihe verengen. Der add_type-Index wird die Suche weiter einschränken.

Zweitens normalisiert diese repetitiven Wert, sonst werden Sie am Ende Probleme haben, die Datenintegrität zu erhalten (stellen Sie sich vor, einige speichern den Namen der Stadt mit Tippfehler). Außerdem kostet das Laden großer Datenmengen in DBMS sehr viele Ressourcen. Ja, es ist "unpraktisch", sich diesen Daten anzuschließen, das wird Sie auf lange Sicht retten. Ohne Normalisierung belegt jede Zeile mindestens 530 Bytes, wenn das Ergebnis 50k Zeilen zurückgibt, dann 530bytes x 50k = leicht 25MB vor der Aggregation (Vor der Sortierung)

Ohne die LIMIT 1 wird diese Abfrage definitiv mehr als wenige nehmen Minuten, da es versucht, die ganze 13-Millionen-Zeile zu durchqueren, riesige Daten in den Speicher zu sammeln.

0

Da praktisch alle Einträge für Brasilien sind, können wir wahrscheinlich die country ignorieren.

WHERE addr_type = 4 
    AND ip_start <= INET6_ATON('XXX.XX.XX.') 
    ORDER BY ip_start DESC; 

benötigt

INDEX(addr_type, ip_start) 

Insbesondere mit dem "= konstant" starten, dann gehen Sie zum 'Reichweite'. Die ORDER BY sollte in der gleichen Optimierung konsumiert werden.

Wenn stattdessen Sie fügen `UND Land = 'BR', dann müssen Sie:

INDEX(country, addr_type, ip_start) 

(country und addr_type können in beliebiger Reihenfolge, aber ip_start muss letzte Mal gewesen sein.)

Sie könnten den Typ loswerden, da LENGTH(INET6_ATON(...)) 4 oder 16 ist, je nachdem, ob es IPv4 oder IPv6 ist.

Ich glaube nicht, dass Ihre ursprüngliche Abfrage nicht so lange gedauert haben sollte. Bitte tun Sie dies für weitere Fehlersuche:

FLUSH STATUS; 
SELECT ...; 
SHOW SESSION STATUS LIKE 'Handler%';