2010-12-06 16 views
1

einen effektiven Index erstellen habe ich einen Web-Server access_log auf eine MySQL-Tabelle umgewandelt, sieht es wie folgt aus:Wie für folgende Abfrage

CREATE TABLE `access_log` (
`timestamp` int(11) NOT NULL default '0', 
`visitorid` int(11) default NULL, 
`url` int(11) default NULL, 
`params` int(11) default NULL, 
`status` smallint(3) NOT NULL default '0', 
`bytes` int(20) NOT NULL default '0', 
`referrer` int(11) default NULL, 
`refparams` int(11) default NULL, 
`useragentid` int(11) default NULL, 
`keywords` int(11) default NULL, 
`country` char(3) default '', 
`crawl` int(1) NOT NULL default '0', 
`sessionid` int(11) default NULL, 
KEY `timestamp` (`timestamp`), 
KEY `visitorid` (`visitorid`), 
KEY `url` (`url`), 
KEY `referrer` (`referrer`), 
KEY `keywords` (`keywords`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1 PACK_KEYS=1; 

Ich habe eine Abfrage, die für eine „Most Popular Pages“ Bericht erzeugt einen bestimmten Datumsbereich, sieht ein Beispiel wie folgt aus:

select url, 
count(distinct visitorid) as visitors, 
count(*) as hits 
from access_log where 
timestamp >=1270072800 and timestamp <=1272664799 
and crawl=0 
group by url order by visitors desc limit 100; 

diese Abfrage wird ziemlich langsam, wenn es eine Menge von Datensätzen in der Tabelle sind.

Abhängig vom Zeitstempelbereich in Bezug auf die Gesamtzahl der Datensätze in der Tabelle, sagt der Optimierer, dass er entweder den 'Zeitstempel' oder den 'URL' Schlüssel verwenden wird. Aber, es erwähnt immer 'Verwenden wo; Verwenden von temporär; Verwenden von filesort '

Gibt es eine Möglichkeit, ich könnte einen kombinierten Index erstellen, die die Ausführungszeit dieser Abfrage verbessern würde?

Ich habe die folgenden Kombinationen ausprobiert, aber der Optimierer scheint sie zu ignorieren:

  1. idx (Zeitstempel, url, visitorid, kriechen)
  2. idx (url, visitorid, krabbeln, Zeitstempel)

Alle Vorschläge oder Hinweise, was ich vermisse, würde geschätzt werden.

Danke!

+0

Wie wäre es mit einem einfachen Index für Zeitstempel? –

+0

Die Tabelle hat bereits einen einfachen Index für den Zeitstempel, ich versuche etwas zu finden, das mir mehr Geschwindigkeit gibt, danke – Michael

+0

Warum versuchen Sie, einen einzigen kombinierten Index zu erstellen? – Donnie

Antwort

0

Sie möchten also URLs nach Beliebtheit in einem bestimmten Zeitraum bewerten. Zusammengesetzter Index auf (URL, visitorid) würde Ihnen Popularität geben. Composite-Index auf (Zeitstempel, URL) würde Ihnen die URLs in Zeitraum besuchen. Warum nicht beide Indizes versuchen, und tritt eine gegen eine Inline-Ansicht, so etwas wie diese (nicht sicher über die genaue Syntax für die Inline-Ansichten in mysql):

 select distinct URL from log as Log1 
        where visitdatetime > x and visitdatetime< y 


     join 

     (select url, count(distinct visitorid) as DistinctVisitors 
     from log 
     group by url 
     -- having count(distinct visitorid) > {some cutoff value greater than 1} 
     -- try the composite index (url, visitorid, visitdate) 
     having vistdate > x and visitdate < y 
     ) as Log2 


     on Log1.url = log2.url 

     order by DistinctVisitors desc 
+0

danke für den Vorschlag, ich werde es jetzt versuchen – Michael

+0

Leider dieser Ansatz funktioniert nicht. Da der Timestamp nicht zur Einschränkung des Log2-Abfrageteils verwendet wird, zählt er grundsätzlich Besucheridentitäten für die gesamte Tabelle, da die URL von Log1 in einem beliebigen Zeitbereich erscheinen kann und der Join wirklich nichts bewirkt.Wenn ich Timestamp zu Log2 hinzufüge, bin ich im Grunde wieder da, wo ich angefangen habe. Außerdem weiß ich vorher nicht, was ein vernünftiger Cutoff-Wert ist, daher muss ich sortieren und auf 100 begrenzen. Danke für den Gedanken! Irgendwelche anderen Vorschläge ? – Michael

+0

Wie wäre es mit Composite-Index (URL, Besucher, Visitdate) für die Log2-Inline-Ansicht und HAVING visitdate> x und visitdate Tim

0

Partition Ihrer Zugriffsprotokolle in mehrere Tabellen, und nur Führen Sie diese Abfrage über die Tabellen innerhalb Ihres Datumsbereichs aus.

Erstellen Sie Übersichtstabellen mit den Daten, die auf täglicher/wöchentlicher/monatlicher Basis voraggregiert sind, um die Menge an Daten zu reduzieren, die zum Erstellen eines Berichts geknirscht werden muss. Nachdem die Protokolldateien des Tages importiert wurden, werden die Daten aggregiert, indem der Zeitstempel auf Stundengrenzen und dann auf Taggrenzen usw. heruntergezählt wird.

+0

Danke für den ausgezeichneten Vorschlag. Ich werde auf jeden Fall versuchen, die Tabelle in mehrere aufzuteilen. Aber bedenken Sie dies, sagen wir, die Daten sind bereits in eine Tabelle pro Monat aufgeteilt und sie hat immer noch eine Menge Datensätze (was der Fall ist). Jetzt sage ich, dass ich ein paar Tage von dieser Tabelle abfragen möchte. Ich kann ein Aggregat nicht für Tage verwenden, da eine Summe (tägliche Besucher) für diesen Zeitraum anders ist als eine Zählung (eindeutige Besucher-ID) über den tatsächlichen Zeitraum. Sehen Sie eine Möglichkeit, die Abfrage zu beschleunigen, da keine andere Partitionierung oder Voraggregation vorgenommen werden kann? d.h. ein besserer Index? – Michael

+0

Ich glaube nicht, dass es eine "goldene Kugel" gibt, die auf einen Index antwortet, der die Dinge nur schön machen lässt. Sicherlich kann ich keinen sehen, daher meine Vorschläge, das Problem aus einem anderen Blickwinkel anzugreifen. – araqnid

+0

Wenn Sie für jeden Tag aggregiert haben (URL, Besucher-ID, Anzahl (*) als Treffer), wären Sie dann in der Lage, diese täglichen Aggregate zu einem gewissen Grad zu verwenden, nicht wahr? d. h., versuchen Sie nicht, vorne vollständig zu aggregieren, sondern reduzieren Sie die Detailmenge auf das erforderliche Minimum. Wenn "Treffer" in dieser Kombination immer nur 1 ist, ist das natürlich nicht allzu nützlich ... trotzdem könnte man die Breite dieser Tabelle erheblich reduzieren und einen besseren Speicherverbrauch erzielen, obwohl es so aussieht, als wäre man gegangen etwas Anstrengung, den Tisch bereits zu verengen. – araqnid

Verwandte Themen