Вы должны прочитать следующее и немного узнать о преимуществах хорошо спроектированной таблицы innodb и о том, как лучше всего использовать кластерные индексы - доступно только с 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/
затем спроектируйте свою систему в соответствии со следующим упрощенным примером:
Пример схемы (упрощенно)
Важными особенностями являются то, что в таблицах используется механизм innodb, и первичный ключ для таблицы потоков больше не является единственным ключом auto_incrementing, а составным кластеризованным ключом , основанным на комбинации forum_id и thread_id. например,
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
...
Каждая строка форума содержит счетчик с именем next_thread_id (unsigned int), который поддерживается триггером и увеличивается каждый раз при добавлении темы в данный форум. Это также означает, что мы можем хранить 4 миллиарда потоков на форуме, а не 4 миллиарда потоков, если использовать один первичный ключ auto_increment для 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
Недостатком использования составного ключа является то, что вы больше не можете просто выбрать поток по одному значению ключа следующим образом:
select * from threads where thread_id = y;
вам нужно сделать:
select * from threads where forum_id = x and thread_id = y;
Тем не менее, код вашего приложения должен знать, какой форум просматривает пользователь, поэтому его не сложно реализовать - сохраните просматриваемый в данный момент forum_id в переменной сеанса или в скрытом поле формы и т. Д. *
Вот упрощенная схема:
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 ;
Вы, возможно, заметили, что я включил response_count как часть первичного ключа, что немного странно, так как составная часть (forum_id, thread_id) уникальна сама по себе. Это всего лишь оптимизация индекса, которая сохраняет некоторые операции ввода-вывода при выполнении запросов, использующих response_count. Пожалуйста, обратитесь к 2 ссылкам выше для получения дополнительной информации об этом.
Примеры запросов
Я все еще загружаю данные в мои таблицы примеров, и до сих пор у меня загружено прибл. 500 миллионов строк (вдвое меньше, чем ваша система). Когда процесс загрузки будет завершен, я должен ожидать примерно:
250 forums * 5 million threads = 1250 000 000 (1.2 billion rows)
Я специально сделал, что некоторые форумы содержат более 5 миллионов тем, например, форум 65 содержит 15 миллионов тем:
forum_id title next_thread_id
======== ===== ==============
65 forum 65 15000000 -- ooh a big one
Время выполнения запроса
select sum(next_thread_id) from forums;
sum(next_thread_id)
===================
539,155,433 (500 million threads so far and still growing...)
при innodb суммирование next_thread_ids для подсчета общего количества потоков происходит намного быстрее, чем обычно:
select count(*) from threads;
Сколько тем в форуме 65:
select next_thread_id from forums where forum_id = 65
next_thread_id
==============
15,000,000 (15 million)
опять же, это быстрее, чем обычно:
select count(*) from threads where forum_id = 65
Хорошо, теперь мы знаем, что у нас около 500 миллионов потоков, а форум 65 имеет 15 миллионов потоков - давайте посмотрим, как работает схема:)
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
Для меня это выглядит довольно производительно - так что это единственная таблица с 500+ миллионами строк (и растущая) с запросом, который покрывает 15 миллионов строк за 0,02 секунды (при загрузке!)
Дальнейшие оптимизации
Это будет включать:
и т.д ...
надеюсь, что вы найдете этот ответ полезным:)