Mysql
 sql >> Datenbank >  >> RDS >> Mysql

MySQL und NoSQL:Helfen Sie mir, das Richtige auszuwählen

Sie sollten das Folgende lesen und ein wenig über die Vorteile einer gut gestalteten innodb-Tabelle lernen und erfahren, wie Sie Clustered-Indizes am besten verwenden - nur verfügbar mit innodb !

http://dev.mysql.com/doc /refman/5.0/en/innodb-index-types.html

http://www. xaprb.com/blog/2006/07/04/how-to-exploit-mysql-index-optimizations/

dann entwerfen Sie Ihr System etwas nach dem folgenden vereinfachten Beispiel:

Beispielschema (vereinfacht)

Die wichtigen Merkmale sind, dass die Tabellen die Innodb-Engine verwenden und der Primärschlüssel für die Threads-Tabelle kein einzelner auto_incrementing-Schlüssel mehr ist, sondern ein zusammengesetzter clustered Schlüssel basierend auf einer Kombination aus forum_id und thread_id. z. B.

threads - primary key (forum_id, thread_id)

forum_id    thread_id
========    =========
1                   1
1                   2
1                   3
1                 ...
1             2058300  
2                   1
2                   2
2                   3
2                  ...
2              2352141
...

Jede Forumszeile enthält einen Zähler namens next_thread_id (unsigned int), der von einem Trigger verwaltet wird und jedes Mal erhöht wird, wenn ein Thread zu einem bestimmten Forum hinzugefügt wird. Das bedeutet auch, dass wir 4 Milliarden Threads pro Forum statt 4 Milliarden Threads insgesamt speichern können, wenn ein einziger auto_increment-Primärschlüssel für thread_id verwendet wird.

forum_id    title   next_thread_id
========    =====   ==============
1          forum 1        2058300
2          forum 2        2352141
3          forum 3        2482805
4          forum 4        3740957
...
64        forum 64       3243097
65        forum 65      15000000 -- ooh a big one
66        forum 66       5038900
67        forum 67       4449764
...
247      forum 247            0 -- still loading data for half the forums !
248      forum 248            0
249      forum 249            0
250      forum 250            0

Der Nachteil der Verwendung eines zusammengesetzten Schlüssels besteht darin, dass Sie einen Thread nicht mehr einfach anhand eines einzelnen Schlüsselwerts wie folgt auswählen können:

select * from threads where thread_id = y;

Sie müssen Folgendes tun:

select * from threads where forum_id = x and thread_id = y;

Ihr Anwendungscode sollte jedoch wissen, welches Forum ein Benutzer durchsucht, so dass es nicht gerade schwierig zu implementieren ist - speichern Sie die aktuell angezeigte forum_id in einer Sitzungsvariablen oder einem versteckten Formularfeld usw...

Hier ist das vereinfachte Schema:

drop table if exists forums;
create table forums
(
forum_id smallint unsigned not null auto_increment primary key,
title varchar(255) unique not null,
next_thread_id int unsigned not null default 0 -- count of threads in each forum
)engine=innodb;


drop table if exists threads;
create table threads
(
forum_id smallint unsigned not null,
thread_id int unsigned not null default 0,
reply_count int unsigned not null default 0,
hash char(32) not null,
created_date datetime not null,
primary key (forum_id, thread_id, reply_count) -- composite clustered index
)engine=innodb;

delimiter #

create trigger threads_before_ins_trig before insert on threads
for each row
begin
declare v_id int unsigned default 0;

  select next_thread_id + 1 into v_id from forums where forum_id = new.forum_id;
  set new.thread_id = v_id;
  update forums set next_thread_id = v_id where forum_id = new.forum_id;
end#

delimiter ;

Sie haben vielleicht bemerkt, dass ich answer_count als Teil des Primärschlüssels eingefügt habe, was ein bisschen seltsam ist, da (forum_id, thread_id) Composite an sich einzigartig ist. Dies ist nur eine Indexoptimierung, die einige I/O-Vorgänge einspart, wenn Abfragen ausgeführt werden, die respond_count verwenden. Weitere Informationen dazu finden Sie unter den beiden obigen Links.

Beispielabfragen

Ich lade immer noch Daten in meine Beispieltabellen und habe bisher ca. 500 Millionen Zeilen (halb so viele wie Ihr System). Wenn der Ladevorgang abgeschlossen ist, sollte ich ungefähr erwarten:

250 forums * 5 million threads = 1250 000 000 (1.2 billion rows)

Ich habe einige der Foren absichtlich so gestaltet, dass sie mehr als 5 Millionen Threads enthalten, zum Beispiel hat Forum 65 15 Millionen Threads:

forum_id    title   next_thread_id
========    =====   ==============
65        forum 65      15000000 -- ooh a big one

Laufzeiten abfragen

select sum(next_thread_id) from forums;

sum(next_thread_id)
===================
539,155,433 (500 million threads so far and still growing...)

Unter innodb ist das Summieren der next_thread_ids zu einer Gesamtanzahl von Threads viel schneller als üblich:

select count(*) from threads;

Wie viele Threads hat Forum 65:

select next_thread_id from forums where forum_id = 65

next_thread_id
==============
15,000,000 (15 million)

Auch dies ist schneller als üblich:

select count(*) from threads where forum_id = 65

Ok, jetzt wissen wir, dass wir bisher ungefähr 500 Millionen Threads haben und Forum 65 hat 15 Millionen Threads - mal sehen, wie das Schema funktioniert :)

select forum_id, thread_id from threads where forum_id = 65 and reply_count > 64 order by thread_id desc limit 32;

runtime = 0.022 secs

select forum_id, thread_id from threads where forum_id = 65 and reply_count > 1 order by thread_id desc limit 10000, 100;

runtime = 0.027 secs

Sieht für mich ziemlich performant aus - das ist also eine einzelne Tabelle mit über 500 Millionen Zeilen (und wächst) mit einer Abfrage, die 15 Millionen Zeilen in 0,02 Sekunden abdeckt (unter Last!)

Weitere Optimierungen

Dazu gehören:

  • Partitionierung nach Bereich

  • Sharding

  • Geld und Hardware darauf zu werfen

usw...

Ich hoffe, Sie finden diese Antwort hilfreich :)