sql >> Databasteknik >  >> RDS >> Mysql

MySQL och NoSQL:Hjälp mig att välja rätt

Du bör läsa följande och lära dig lite om fördelarna med en väldesignad innodb-tabell och hur man bäst använder klustrade index - endast tillgängligt med 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/

designa sedan ditt system något i stil med följande förenklade exempel:

Exempelschema (förenklat)

De viktiga funktionerna är att tabellerna använder innodb-motorn och primärnyckeln för trådtabellen är inte längre en enda auto_incrementing-nyckel utan en sammansatt klustrad nyckel baserad på en kombination av forum_id och thread_id. t.ex.

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
...

Varje forumrad innehåller en räknare som heter next_thread_id (osignerad int) som underhålls av en trigger och ökar varje gång en tråd läggs till i ett givet forum. Detta innebär också att vi kan lagra 4 miljarder trådar per forum istället för 4 miljarder trådar totalt om vi använder en enda auto_increment-primärnyckel för thread_id.

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

Nackdelen med att använda en sammansatt nyckel är att du inte längre bara kan välja en tråd med ett enda nyckelvärde enligt följande:

select * from threads where thread_id = y;

du måste göra:

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

Din applikationskod bör dock vara medveten om vilket forum en användare surfar på så det är inte direkt svårt att implementera - lagra det forum_id som visas för närvarande i en sessionsvariabel eller dolt formulärfält etc...

Här är det förenklade schemat:

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 ;

Du kanske har märkt att jag har inkluderat reply_count som en del av primärnyckeln, vilket är lite konstigt eftersom (forum_id, thread_id) komposit är unikt i sig. Detta är bara en indexoptimering som sparar en del I/O när frågor som använder reply_count exekveras. Se de två länkarna ovan för mer information om detta.

Exempel på frågor

Jag laddar fortfarande data i mina exempeltabeller och hittills har jag laddat ca. 500 miljoner rader (hälften så många som ditt system). När laddningsprocessen är klar bör jag räkna med att ha ca:

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

Jag har medvetet gjort att några av forumen innehåller mer än 5 miljoner trådar till exempel, forum 65 har 15 miljoner trådar:

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

Frågekörningstider

select sum(next_thread_id) from forums;

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

under innodb summering av next_thread_ids för att ge ett totalt antal trådar är mycket snabbare än det vanliga:

select count(*) from threads;

Hur många trådar har forum 65:

select next_thread_id from forums where forum_id = 65

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

igen detta är snabbare än vanligt:

select count(*) from threads where forum_id = 65

Ok nu vet vi att vi har cirka 500 miljoner trådar hittills och forum 65 har 15 miljoner trådar - låt oss se hur schemat fungerar :)

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

Ser ganska presterande ut för mig - så det är en enskild tabell med 500+ miljoner rader (och växer) med en fråga som täcker 15 miljoner rader på 0,02 sekunder (medan den är belastad!)

Ytterligare optimeringar

Dessa skulle inkludera:

  • partitionering efter intervall

  • skärning

  • kasta pengar och hårdvara på det

osv...

hoppas du tycker att det här svaret är användbart :)



  1. Beräkna decil från frekvens i MySQL

  2. Hur simulerar man UNPIVOT i Access?

  3. packa upp postgresql-arrayen i rader

  4. Hur IFNULL() fungerar i MariaDB