SELFPHP: Version 5.8.2 Befehlsreferenz - Tutorial – Kochbuch – Forum für PHP Einsteiger und professionelle Entwickler

SELFPHP


Professional CronJob-Service

Suche



CronJob-Service    
bei SELFPHP mit ...



 + minütlichen Aufrufen
 + eigenem Crontab Eintrag
 + unbegrenzten CronJobs
 + Statistiken
 + Beispielaufrufen
 + Control-Bereich

Führen Sie mit den CronJobs von SELFPHP zeitgesteuert Programme auf Ihrem Server aus. Weitere Infos



:: Buchempfehlung ::

Fortgeschrittene CSS-Techniken

Fortgeschrittene CSS-Techniken zur Buchempfehlung
 

:: Anbieterverzeichnis ::

Globale Branchen

Informieren Sie sich über ausgewählte Unternehmen im Anbieterverzeichnis von SELFPHP  

 

:: Newsletter ::

Abonnieren Sie hier den kostenlosen SELFPHP Newsletter!

Vorname: 
Name:
E-Mail:
 
 

Zurück   PHP Forum > SELFPHP > MySQLi/PDO/(MySQL)

MySQLi/PDO/(MySQL) Anfänger, Fortgeschrittene oder Experten können hier Fragen und Probleme rund um MySQLi/PDO/(MySQL) diskutieren

Antwort
 
Themen-Optionen Ansicht
  #1  
Alt 22.10.2008, 10:16:05
mgutt mgutt ist offline
Anfänger
 
Registriert seit: May 2008
Beiträge: 65
Wie SELECT mit Suche nach String beschleunigen?

Hallo,

ich ermittle statistisch, wie oft welches Wort auf meinen Seiten gesucht wird.

Jedes Wort erhält eine ID (autoincrement) und alle folgenden Abfragen beziehen sich dann aus Geschwindigkeitsgründen auf die ID (z.B. um die letzte Suchzeit oder die Anzahl der Suchversuche zu aktualisieren).

Doch leider ist bereits die erste Abfrage zu langsam (aktuell 1 Millionen Einträge):
Code:
SELECT id
FROM keywords
WHERE kw = '" . mysql_real_escape_string($q) . "'"
Sie ist an sich nicht langsam, doch dadurch, dass die Tabelle immer größer wird, merkt man einfach, dass die Ausführungszeit nachlässt.

Nun dachte ich an folgende Varianten, wo ich mir aber nicht sicher bin, welche den meisten Erfolg verspricht:

V1:
Ich lese den ersten Buchstaben von $q aus und wandle ihn in einen INT um:
Code:
$first = ord($q{0})
Und vergleiche diesen an Hand einer neuen Spalte:
Code:
SELECT id
FROM keywords
WHERE first = '" . $first . "'
AND kw = '" . mysql_real_escape_string($q) . "'"
V2:
Ich erstelle für jeden Buchstaben eine eigene Tabelle:
Code:
SELECT id
FROM keywords_" . $first . "
WHERE kw = '" . mysql_real_escape_string($q) . "'"
Bei späteren Abfragen benötige ich dann weiterhin $first, um die richtige Tabelle aktualisieren zu können.

Denkbarer Nachteil ist hier die Darstellung von "häufigsten" bzw. "letzten" Suchwörtern bei der statistischen Auswertung. Ich müsste dann erst alle Tabellen auslesen und die mit in eine FROM bringen oder ich müsste für jede Tabelle einzeln Statistiken machen und diese nachträglich zusammenfügen.

Gruß

Geändert von mgutt (22.10.2008 um 10:25:35 Uhr)
Mit Zitat antworten
  #2  
Alt 22.10.2008, 11:34:20
Crisps Crisps ist offline
Junior Member
 
Registriert seit: Oct 2008
Alter: 47
Beiträge: 274
AW: Wie SELECT mit Suche nach String beschleunigen?

Zitat:
Zitat von mgutt Beitrag anzeigen
Code:
SELECT id
FROM keywords
WHERE kw = '" . mysql_real_escape_string($q) . "'"
Hat das kw Feld einen Index?

Und was zeigt die Ausgabe der folgenden Query an:

Code:
EXPLAIN SELECT id
          FROM keywords
         WHERE kw = '" . mysql_real_escape_string($q) . "'"

Geändert von Crisps (22.10.2008 um 11:37:07 Uhr)
Mit Zitat antworten
  #3  
Alt 22.10.2008, 12:52:38
mgutt mgutt ist offline
Anfänger
 
Registriert seit: May 2008
Beiträge: 65
AW: Wie SELECT mit Suche nach String beschleunigen?

> Index
Nein, weil ein Index auf VARCHAR ziemlich unsinnig ist, wenn VARCHAR wie bei mir viele unterschiedliche Werte mit teilweise langen Phrasen enthält. MySQL dazu:
http://www.mysql.com/news-and-events...000000075.html

Es wird also empfohlen nur einen Teil des VARCHAR zu nutzen, z.B. die ersten 10 Zeichen. Daher auch meine Idee, erstmal nur den INT-Wert des ersten Buchstabens zu nutzen, da damit die Filterung schon um den Faktor 20-40 reduziert wird und im Gegensatz zu MySQLs Tipps sogar ein noch schnellerer INT-Vergleich möglich ist (so die Idee).

Einen INDEX auf kw würde die Anzahl der Reihen auf schätzungsweise 943k reduzieren, also nicht wirklich viel und es sind identisch viele Reihen wie der INDEX auf project, da die Keywords pro Projekt ermittelt werden und damit in jeder Zeile ein anderes Keyword steht.

Bei einem Test mit einer anderen Tabelle ähnlicher Größe resultierte ein Index auf VARCHAR einen großen Performance-Nachteil, daher habe ich mich bisher nicht getraut einen bei dieser Tabelle zu setzen. Wenn Du aber meinst, dass es sinnvoll ist, dann teste ich das gerne noch mal.

> EXPLAIN
Nur auf kw:
Zitat:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE keywords ALL NULL NULL NULL NULL 1090221 Using where
auf kw und project
Zitat:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE keywords ref project project 3 const 943219 Using where
auf kw, project und first
Zitat:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE keywords ref first,project first 1 const 17778 Using where
EDIT:
Den Index auf project habe ich wieder entfernt, weil dadurch ein ORDER BY auf search_time 10 und mehr Sekunden dauert.

Gruß

Geändert von mgutt (22.10.2008 um 13:25:03 Uhr)
Mit Zitat antworten
  #4  
Alt 22.10.2008, 14:10:07
Crisps Crisps ist offline
Junior Member
 
Registriert seit: Oct 2008
Alter: 47
Beiträge: 274
AW: Wie SELECT mit Suche nach String beschleunigen?

Ich hab mir deinen Link mal angesehen und kann dort nichts finden was einem Index auf Varchar Spalten wiedersprechen würde (Was mich auch sehr überrascht hätte). Es wird dort nur gesagt, dass Ein Index auf Varchar nicht sehr platzsparend ist (nicht so wild) und langsam sei (langsam beim einfügen) - Das ist aber alles relativ, denn bei der Abfrage selbst wirst Du einen deutlichen Geschwindigkeitsvorteil merken - die Inserts selbst brauchen vielleicht ein paar tausendstel (!) Sekunden länger als sonst.

Zitat:
Es wird also empfohlen nur einen Teil des VARCHAR zu nutzen, z.B. die ersten 10 Zeichen. Daher auch meine Idee, erstmal nur den INT-Wert des ersten Buchstabens zu nutzen, da damit die Filterung schon um den Faktor 20-40 reduziert wird und im Gegensatz zu MySQLs Tipps sogar ein noch schnellerer INT-Vergleich möglich ist (so die Idee).
Ich glaube nicht, dass Du das so umständlich machen musst. Kopier doch mal deine gesamte Tabelle auf eine zweite DB, in der Du das ganze dann durchtesten kannst.

Das mit der reduzierten Indexlänge ist schon mal ein guter Ansatz:

ALTER TABLE keywords ADD INDEX ix_first (kw (1));

Hier werden nur die ersten Buchstaben deiner Keywords indexiert. Ich glaube Du wirst staunen um wie viel schneller so ein einfacher Index bereits deine Abfragen beschleunigt. Ich würde aber mit der Indexlänge noch etwas höher gehen, wie hoch? Ich würde mal sagen so um die ersten 6-8, was natürlich auch von der Wörterlänge abhängt. Aber wie gesagt, probier das doch mal auf einer seperaten Datenbank/Tabelle aus.


Zitat:
Bei einem Test mit einer anderen Tabelle ähnlicher Größe resultierte ein Index auf VARCHAR einen großen Performance-Nachteil, daher habe ich mich bisher nicht getraut einen bei dieser Tabelle zu setzen. Wenn Du aber meinst, dass es sinnvoll ist, dann teste ich das gerne noch mal.
Ich bin mir sehr sicher. ;) Deine negativen Erfahrungen mit einer anderen Tabelle - hm, nun das kann ich von hier natürlich nicht beurteilen, es gibt allerdings keinen Grund, dass Indexe auf Varchar generell einen Performance Nachteil hätten.

Zitat:
auf kw und project
Wenn du eine solche Abfrage hast, wäre es unter Umständen noch besser einen Composite-Index anzulegen - etwa so:

ALTER TABLE keywords ADD INDEX ix_projekte_kw (projekte, kw (6));

Da MySQL nur einen Index pro Abfrage nutzen kann, legen wir einen Index an der die Projekt Spalte und die ersten sechs Buchstaben der Keywords kombiniert. Die Where-Condition muss dann aber auch mit "WHERE projekte AND kw = ''" beginnen, nicht andersrum.

Geändert von Crisps (22.10.2008 um 14:14:26 Uhr)
Mit Zitat antworten
  #5  
Alt 22.10.2008, 15:28:39
defabricator defabricator ist offline
Senior Member
 
Registriert seit: Sep 2007
Ort: Potsdam
Alter: 55
Beiträge: 1.020
AW: Wie SELECT mit Suche nach String beschleunigen?

Zitat:
Use index on prefix: Indexes on varchar columns take a lot of space and so generally can be slow. If your data is very different even by the start of the string you may benefit from creating index on column prefix:
ALTER TABLE MYTABLE ADD KEY NAME_KEYT (NAME(20))
Das solltest Du tun - wenn Du MyISAM verwendest.
Damit begrenzt Du den Index (in diesem Beispiel) auf die ersten zwanzig Zeichen. Deine Vorgehensweise, nur den ersten Buchstaben zu betrachten, entspricht (und das ist mit viel Vorsicht zu genießen) ungefähr einem Index Feldname(1) - nur sinnvoller.

p.s.: Das soll jetzt übrigens nicht heißen, dass Du einen Index der Länge 1 setzen sollst ;) Aber vielleicht 4, 8, 20 ....je nachdem, wie Deine Daten aussehen.
__________________
Wat der Bauer nich kennt, dit frisster nich.

Geändert von defabricator (22.10.2008 um 15:33:32 Uhr)
Mit Zitat antworten
  #6  
Alt 22.10.2008, 17:11:08
mgutt mgutt ist offline
Anfänger
 
Registriert seit: May 2008
Beiträge: 65
AW: Wie SELECT mit Suche nach String beschleunigen?

>langsam beim einfügen
Das gilt nicht nur beim INSERT, sondern auch beim SELECT. Umso größer der Datensatz, umso mehr Festplattenzugriff ist nötig, um den Zieldatensatz zu finden. Besonders wenn es so viele Zeilen sind wie in der Tabelle. Die Begrenzung des Indexes auf die ersten X Zeichen ist im Grund nichts anderes als was ich bei V1 und V2 vorschlage, nur ist eben die Frage was besser ist (V1, V2 oder begrenzender Index).

> Composite-Index
Indexe über mehrere Spalten verstehe ich ehrlich gesagt nicht. Immer wieder wenn ich die einsetze ist das Resultat grausam. Gibt es dazu irgendwo Erklärungen mit Beispielen wann ich mehrere Indexe setzen sollte? Mir fehlt da immer das Verständnis, wenn ich 3-4 WHERE-Vergleiche habe und 1-2 ORDER BY, welche Spalten einen einzelnen Index brauchen und welche multiple. Häufig wird die eine Abfrage dadurch schneller und eine andere wird grottenlangsam.

>Deine Vorgehensweise ... entspricht ... ungefähr einem Index Feldname(1)
Genau so bin ich auch auf meine Variante gekommen. Die Frage ist jetzt was besser ist. Ich glaube, dass wenn ich über INT vergleiche, bessere Resultate erhalte, als wenn ich mit einem begrenzenden Index arbeite.

>oben genannter Link
In dem Link steht ja zusätzlich, dass VARCHAR(255) langsamer ist als VARCHAR(50). Kann ich die Tabelle so sortieren, dass der längste Wert ermittelt werden kann? Dann würde ich analysieren, wie lang mein längster Wert ist und VARCHAR entsprechend optimieren. Ansonsten würde müsste ich zeilenweise alles durcharbeiten und per PHP auswerten.
Mit Zitat antworten
  #7  
Alt 22.10.2008, 17:31:57
Crisps Crisps ist offline
Junior Member
 
Registriert seit: Oct 2008
Alter: 47
Beiträge: 274
AW: Wie SELECT mit Suche nach String beschleunigen?

Zitat:
Das gilt nicht nur beim INSERT, sondern auch beim SELECT. Umso größer der Datensatz, umso mehr Festplattenzugriff ist nötig, um den Zieldatensatz zu finden. Besonders wenn es so viele Zeilen sind wie in der Tabelle.
Gut, wenn dir so ein minimaler Verlust wichtiger ist als ein deutlich beschleunigte SELECT Abfrage.....................

Zitat:
Die Begrenzung des Indexes auf die ersten X Zeichen ist im Grund nichts anderes als was ich bei V1 und V2 vorschlage, nur ist eben die Frage was besser ist (V1, V2 oder begrenzender Index).
Begrenzter Index. Mit den Datensätzen direkt in MySQL zu arbeiten ist eigentlich immer vorzuziehen und auch sauberer.

Zitat:
Indexe über mehrere Spalten verstehe ich ehrlich gesagt nicht. Immer wieder wenn ich die einsetze ist das Resultat grausam. Gibt es dazu irgendwo Erklärungen mit Beispielen wann ich mehrere Indexe setzen sollte? Mir fehlt da immer das Verständnis, wenn ich 3-4 WHERE-Vergleiche habe und 1-2 ORDER BY, welche Spalten einen einzelnen Index brauchen und welche multiple. Häufig wird die eine Abfrage dadurch schneller und eine andere wird grottenlangsam.
Das kann man nicht so pauschal sagen, dazu muss man die Query genauer kennen.

Zitat:
Kann ich die Tabelle so sortieren, dass der längste Wert ermittelt werden kann? Dann würde ich analysieren, wie lang mein längster Wert ist und VARCHAR entsprechend optimieren.
Code:
SELECT MAX(LENGTH(kw)) FROM keywords;
(Kann bei deiner großen DB ggf. länger dauern)

Geändert von Crisps (22.10.2008 um 17:32:49 Uhr)
Mit Zitat antworten
  #8  
Alt 22.10.2008, 17:36:50
defabricator defabricator ist offline
Senior Member
 
Registriert seit: Sep 2007
Ort: Potsdam
Alter: 55
Beiträge: 1.020
AW: Wie SELECT mit Suche nach String beschleunigen?

Zitat:
Zitat von mgutt Beitrag anzeigen
Ich glaube, dass wenn ich über INT vergleiche, bessere Resultate erhalte, als wenn ich mit einem begrenzenden Index arbeite.
Was veranlasst Dich zu diesem Glauben?
Ich sehe da erstmal etwas, das Du "per Hand" machen musst, einen Zusätzlichen Funktionsaufruf in PHP+Zuweisung, eine zusätzliche Vergleichsoperation in SQL und einen Eingriff in den "Kernbereich" von dem, was Datenbanken tun sollen. Dafür reicht mir bloßer Glaube als Argument nicht aus ;)
__________________
Wat der Bauer nich kennt, dit frisster nich.
Mit Zitat antworten
  #9  
Alt 22.10.2008, 19:37:50
mgutt mgutt ist offline
Anfänger
 
Registriert seit: May 2008
Beiträge: 65
AW: Wie SELECT mit Suche nach String beschleunigen?

>LENGHT()
Ok, der Name war eigentlich naheliegend ;) Danke!

Es wurde zwar jegliche Länge genutzt, aber auf Grund der prozentualen Verteilung, habe ich VARCHAR auf 100 reduziert.

>Mit den Datensätzen direkt in MySQL zu arbeiten ist eigentlich immer vorzuziehen und auch sauberer.
Nun sauber bringt ja nichts, wenn die genannte Idee schneller ist.

Ich werde aber mal alle Varianten außer V2 durchtesten:

A) Index auf first
Abfrage nach kw: 0.19071723937988
Abfrage nach projekt und kw: 0.22569104194642
Abfrage nach projekt, first und kw: 0.030680880546565
Die Abfrage projekt,first,kw ist damit also 7x schneller als projekt,kw geworden.

B) Mit dem index auf first und kw(5):
Abfrage nach kw: 0.0021519637107848
Abfrage nach projekt und kw: 0.0017872953414916
Abfrage nach projekt, first und kw: 0.0041718840599059
Die Abfrage projekt,kw ist 2x schneller als projekt,first,kw und ingesamt viel schneller als in A) also ist das der richtige Weg

C) Mit dem index auf kw(5):
Abfrage nach kw: 0.0025481438636782
Abfrage nach projekt und kw: 0.0031441688537598

D) Mit dem index auf kw(10):
Abfrage nach kw: 0.0011384558677673
Abfrage nach projekt und kw: 0.0021649360656737

E) Mit dem index auf kw:
Abfrage nach kw: 0.0024761486053465
Abfrage nach projekt und kw: 0.002344229221344

F) Mit dem index auf projekt+kw(10):
Serverabsturz, weil die Abfrage mit WHERE projekt = 1 ORDER BY tries LIMIT 100 zu lange dauert.

G) Mit dem index auf kw(10):
Abfrage nach kw: 0.0022609758377075
Abfrage nach projekt und kw: 0.0017019295692445
Abfrage nach kw und projekt: 0.0020268511772155

Die Tests resultieren übrigens aus dem Schnitt von 100 Abfragen in zufälliger Reihenfolge im Live-Betrieb.

Fazit:
Meine Idee war sinnlos :P Wie man jetzt noch einen Index auf projekt setzen könnte weiß ich nicht. Dem Test zufolge war die Wahl von kw(10) mit die Beste, die ich jetzt auch aktiv nutze.

Wie erkenne ich eigentlich welche Größe der Index haben soll? Ich mein jetzt ergibt der Index 363434 Zeilen, also ca. 1/3 der gesamten Zeilen. Kann man das als Richtwert nehmen?

Geändert von mgutt (22.10.2008 um 20:25:28 Uhr)
Mit Zitat antworten
  #10  
Alt 23.10.2008, 08:02:30
Crisps Crisps ist offline
Junior Member
 
Registriert seit: Oct 2008
Alter: 47
Beiträge: 274
AW: Wie SELECT mit Suche nach String beschleunigen?

Zitat:
Wie erkenne ich eigentlich welche Größe der Index haben soll? Ich mein jetzt ergibt der Index 363434 Zeilen, also ca. 1/3 der gesamten Zeilen. Kann man das als Richtwert nehmen?
Ich würde sagen, dass das von der Wörterlänge abhängt - das habe ich jedenfalls bis vor kurzem so gedacht. Allerdings hat sich bei einem Test von Strings mit etwa 10 Buchstaben und einem zweiten Test mit Strings von 30 Buchstaben gezeigt, dass bei beiden bereits eine Indexlänge von 5-6 reicht, bei einem längeren Index konnte ich praktisch keinen Vorteil messen. Das ganze muss man aber mit den gegebenen Daten ausprobieren.
Mit Zitat antworten
Antwort


Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)
 
Themen-Optionen
Ansicht

Forumregeln
Es ist Ihnen nicht erlaubt, neue Themen zu verfassen.
Es ist Ihnen nicht erlaubt, auf Beiträge zu antworten.
Es ist Ihnen nicht erlaubt, Anhänge hochzuladen.
Es ist Ihnen nicht erlaubt, Ihre Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind aus.
[IMG] Code ist aus.
HTML-Code ist aus.

Gehe zu

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
string wird per Post anders ausgegeben zhamoran PHP Grundlagen 2 07.09.2008 19:38:24
Subquery in select als String niemayd MySQLi/PDO/(MySQL) 3 30.07.2008 10:32:28
select in select verschachteln DerSchatten MySQLi/PDO/(MySQL) 7 19.12.2007 21:22:13
To Many Connections ProGamer11 PHP Grundlagen 0 18.06.2003 23:52:56
Ich willst jetzt wissen - Select * oder nicht Select * CyberAge PHP Grundlagen 22 13.08.2002 17:40:46


Alle Zeitangaben in WEZ +2. Es ist jetzt 11:22:48 Uhr.


Powered by vBulletin® Version 3.8.3 (Deutsch)
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.


© 2001-2024 E-Mail SELFPHP OHG, info@selfphp.deImpressumKontakt