ced*_*vad 40 php mysql cassandra nosql
有一个大的数据库,1,000,000,000行,称为线程(这些线程实际存在,我不是因为我喜欢它而使事情变得更难).线程中只有一些东西,以加快速度:(int id,string hash,int replycount,int dateline(timestamp),int forumid,string title)
查询:
select * from thread where forumid = 100 and replycount > 1 order by dateline desc limit 10000, 100
由于存在1G的记录,因此查询速度非常慢.所以我想,让我们在尽可能多的论坛(类别)中将这1G记录分开!这几乎是完美的.有很多表我搜索的记录较少,而且速度真快.查询现在变为:
select * from thread_{forum_id} where replycount > 1 order by dateline desc limit 10000, 100
99%的论坛(类别)真的更快,因为大多数论坛只有少数主题(100k-1M).但是因为有一些大约有10M的记录,一些查询仍然会变慢(0.1/.2秒,对我的应用来说太多了!我已经在使用索引!).
我不知道如何使用MySQL改进这一点.有办法吗?
对于这个项目,我将使用10台服务器(12GB内存,4x7200rpm硬盘,软件raid 10,四核)
这个想法是简单地在服务器之间拆分数据库,但是上面解释的问题仍然没有得到解决.
如果我在这10台服务器上安装cassandra(通过假设我找到时间让它按预期工作)我应该假设性能提升吗?
我该怎么办?继续使用MySQL与多台机器上的分布式数据库或构建一个cassandra集群?
我被要求发布索引是什么,这里是:
mysql> show index in thread;
PRIMARY id
forumid
dateline
replycount
Run Code Online (Sandbox Code Playgroud)
选择说明:
mysql> explain SELECT * FROM thread WHERE forumid = 655 AND visible = 1 AND open <> 10 ORDER BY dateline ASC LIMIT 268000, 250;
+----+-------------+--------+------+---------------+---------+---------+-------------+--------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+---------+---------+-------------+--------+-----------------------------+
| 1 | SIMPLE | thread | ref | forumid | forumid | 4 | const,const | 221575 | Using where; Using filesort |
+----+-------------+--------+------+---------------+---------+---------+-------------+--------+-----------------------------+
Run Code Online (Sandbox Code Playgroud)
Jon*_*ack 79
您应该阅读以下内容并了解一下设计良好的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
...
Run Code Online (Sandbox Code Playgroud)
每个论坛行都包含一个名为next_thread_id(unsigned int)的计数器,该计数器由触发器维护,并在每次将线程添加到给定论坛时递增.这也意味着如果为thread_id使用单个auto_increment主键,我们每个论坛可以存储40亿个线程,而不是总共40亿个线程.
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
Run Code Online (Sandbox Code Playgroud)
使用复合键的缺点是您不能再按单个键值选择线程,如下所示:
select * from threads where thread_id = y;
Run Code Online (Sandbox Code Playgroud)
你必须做:
select * from threads where forum_id = x and thread_id = y;
Run Code Online (Sandbox Code Playgroud)
但是,您的应用程序代码应该知道用户正在浏览哪个论坛,因此实现起来并不十分困难 - 将当前查看的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 ;
Run Code Online (Sandbox Code Playgroud)
您可能已经注意到我已将reply_count包含在主键中,这有点奇怪,因为(forum_id,thread_id)复合本身是唯一的.这只是一个索引优化,它可以在执行使用reply_count的查询时节省一些I/O. 有关详细信息,请参阅上面的2个链接.
我仍在将数据加载到我的示例表中,到目前为止我已经加载了大约.5亿行(是系统的一半).当加载过程完成后,我应该有大约:
250 forums * 5 million threads = 1250 000 000 (1.2 billion rows)
Run Code Online (Sandbox Code Playgroud)
我故意让一些论坛包含超过500万个线程,例如,论坛65有1500万个线程:
forum_id title next_thread_id
======== ===== ==============
65 forum 65 15000000 -- ooh a big one
Run Code Online (Sandbox Code Playgroud)
select sum(next_thread_id) from forums;
sum(next_thread_id)
===================
539,155,433 (500 million threads so far and still growing...)
Run Code Online (Sandbox Code Playgroud)
在innodb总结下,next_thread_ids给出的总线程数比通常快得多:
select count(*) from threads;
Run Code Online (Sandbox Code Playgroud)
论坛65有多少个主题:
select next_thread_id from forums where forum_id = 65
next_thread_id
==============
15,000,000 (15 million)
Run Code Online (Sandbox Code Playgroud)
再次这比通常更快:
select count(*) from threads where forum_id = 65
Run Code Online (Sandbox Code Playgroud)
好了,我们知道到目前为止我们有大约5亿个线程,而论坛65有1500万个线程 - 让我们看看架构如何执行:)
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
Run Code Online (Sandbox Code Playgroud)
看起来非常高效 - 所以这是一个包含500多万行(并且还在增长)的单个表,其查询在0.02秒内覆盖了1500万行(在加载时!)
这些包括:
按范围划分
分片
扔钱和硬件
等等...
希望你觉得这个答案很有帮助:)
Vic*_*let 24
编辑:您的单列索引是不够的.您至少需要涵盖三个相关列.
更先进的解决方案:更换replycount > 1
与hasreplies = 1
创建一个新的hasreplies
,等于1时场replycount > 1
.完成后,按顺序在三列上创建索引:INDEX(forumid, hasreplies, dateline)
.确保它是支持订购的BTREE索引.
您选择的依据是:
forumid
hasreplies
dateline
执行此操作后,您的查询执行将涉及:
forumid = X
.这是一个对数操作(持续时间:log(论坛数)).hasreplies = 1
(同时仍然匹配forumid = X
).这是一个恒定时间操作,因为hasreplies
只有0或1.我之前关于索引的建议replycount
是不正确的,因为它本来是一个范围查询,因此阻止了使用a dateline
来对结果进行排序(所以你会选择带有回复的线程非常快,但是得到的百万行列表会有在寻找你需要的100个元素之前必须完全分类.
重要提示:虽然这可以在所有情况下提高性能,但是你的巨大OFFSET值(10000!)会降低性能,因为尽管直接通过BTREE阅读,MySQL似乎无法跳过.因此,OFFSET越大,请求就越慢.
我担心OFFSET问题不能通过将计算扩展到多个计算来自动解决(无论如何,你如何跳过并行偏移?)或转移到NoSQL.所有解决方案(包括NoSQL解决方案)将归结为基于模拟OFFSET dateline
(基本上dateline > Y LIMIT 100
代替在偏移处项目的日期LIMIT Z, 100
在哪里).这有效,并消除了与偏移相关的任何性能问题,但阻止直接进入200页中的第100页.Y
Z
归档时间: |
|
查看次数: |
20279 次 |
最近记录: |