Você deve ler o seguinte e aprender um pouco sobre as vantagens de uma tabela innodb bem projetada e a melhor forma de usar índices clusterizados - disponível apenas com 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/
em seguida, projete seu sistema de acordo com as linhas do seguinte exemplo simplificado:
Exemplo de esquema (simplificado)
Os recursos importantes são que as tabelas usam o mecanismo innodb e a chave primária para a tabela de threads não é mais uma única chave auto_incrementing, mas uma clustered composta key baseado em uma combinação de forum_id e thread_id. por exemplo.
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
...
Cada linha do fórum inclui um contador chamado next_thread_id (unsigned int) que é mantido por um gatilho e incrementa toda vez que um tópico é adicionado a um determinado fórum. Isso também significa que podemos armazenar 4 bilhões de threads por fórum em vez de 4 bilhões de threads no total se usarmos uma única chave primária auto_increment para 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
A desvantagem de usar uma chave composta é que você não pode mais selecionar um thread por um único valor de chave da seguinte maneira:
select * from threads where thread_id = y;
você tem que fazer:
select * from threads where forum_id = x and thread_id = y;
No entanto, o código do seu aplicativo deve estar ciente de qual fórum um usuário está navegando, então não é exatamente difícil de implementar - armazene o forum_id atualmente visualizado em uma variável de sessão ou campo de formulário oculto etc ...
Aqui está o esquema simplificado:
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 ;
Você deve ter notado que incluí reply_count como parte da chave primária, o que é um pouco estranho, pois o composto (forum_id, thread_id) é único em si. Esta é apenas uma otimização de índice que economiza algumas E/S quando as consultas que usam reply_count são executadas. Consulte os 2 links acima para obter mais informações sobre isso.
Exemplos de consultas
Ainda estou carregando dados em minhas tabelas de exemplo e, até agora, carreguei um arquivo aprox. 500 milhões de linhas (metade do seu sistema). Quando o processo de carregamento estiver concluído, devo esperar ter aproximadamente:
250 forums * 5 million threads = 1250 000 000 (1.2 billion rows)
Eu deliberadamente fiz alguns dos fóruns conterem mais de 5 milhões de tópicos, por exemplo, o fórum 65 tem 15 milhões de tópicos:
forum_id title next_thread_id
======== ===== ==============
65 forum 65 15000000 -- ooh a big one
Tempos de execução da consulta
select sum(next_thread_id) from forums;
sum(next_thread_id)
===================
539,155,433 (500 million threads so far and still growing...)
no innodb, somar o next_thread_ids para fornecer uma contagem total de threads é muito mais rápido que o normal:
select count(*) from threads;
Quantos tópicos o fórum 65 tem:
select next_thread_id from forums where forum_id = 65
next_thread_id
==============
15,000,000 (15 million)
novamente, isso é mais rápido que o normal:
select count(*) from threads where forum_id = 65
Ok, agora sabemos que temos cerca de 500 milhões de tópicos até agora e o fórum 65 tem 15 milhões de tópicos - vamos ver como o esquema se comporta :)
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
Parece muito bom para mim - então essa é uma única tabela com mais de 500 milhões de linhas (e crescendo) com uma consulta que cobre 15 milhões de linhas em 0,02 segundos (enquanto sob carga!)
Otimizações adicionais
Estes incluiriam:
-
particionamento por intervalo
-
fragmentação
-
jogando dinheiro e hardware nele
etc...
espero que você ache esta resposta útil :)