免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 4142 | 回复: 15
打印 上一主题 下一主题

求一个好的思路,效率问题 【已解决】 [复制链接]

论坛徽章:
1
程序设计版块每日发帖之星
日期:2015-10-07 06:20:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-04-30 09:48 |只看该作者 |倒序浏览
本帖最后由 chenhao392 于 2013-05-01 09:17 编辑

数据描述:

1. 700万条长短不一的string,每一个都有uniq name。
2. 大多数比较短,有些很长 (1Mb+)3. 总共 4Gb +

   生物信息注释: 一个基因组,很多染色体片段。   sample:


   seq1: AAAAAAAAAAA
   seq2: BBBBBBBBBBB

需求:



用户提供,
        1) string name (如seq1)
        2) 起始和结束的位置,如 (20, 60)

server快速返回substring,并在网页上显示。




硬件:


webserver: 2个 CPU,2G内存, FC18, LAMP 网站。
其他电脑支持: 16 CPU, 48Gb 内存, linux.


我的尝试:


mysql 直接存储一个大表,通过内建的length 计算原string长度,修改用户的input,之后通过substr拿到substring。
现在是拿PHP写的,结果需要等待1分钟以上。因为前端是AJAX的,感觉不可忍。


设想方案:


由于webserver的内存和CPU都比较一般。我想是不是可以写一个perl 的CGI。用
Storable (http://search.cpan.org/~ams/Storable-2.24/Storable.pm), BerkeleyDB(http://search.cpan.org/~pmqs/BerkeleyDB-0.51/BerkeleyDB.pod.P
这一类的module 将整个关联数组/hash ,写到硬盘上。再利用perl的substr 提取string 片段。





问题:



1. 请问这样是否能提高效率呢?

   用内存时,用hash搜索string的name,应该是不耗时间的,substr似乎也够快。问题在于,4G的数据,写了hash存硬盘,会影响效率么?



2. 或者有没有更好的想法?



  感谢阅读和任何想法:)



~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
更新:问题已经解决.



感谢楼上的朋友们的建议,测试访问速度基本瞬时了,1s以内。
然后,我并不要求并发数.

to iamlimeng:
数据是相对固定的,分割小文件也绝对会加快速度,谢谢。只是现在的大文件已经让我满足了。

to laputa73:
48G的电脑可以帮忙计算数据,不能对外访问。感谢告知redis的存在,我没有用单纯是不想花时间学redis,就写了个perl. 事实上还是用DB_File 存储hash来实现快速搜索,所以,一定意义上也算 “键值”数据库吧 :)

to soul20040103:
感谢建议。其实昨天我面对的主要的问题是mysql中substr的效率问题,之后想到perl的substr,但是担心perl里面大文件访问也影响速度,抱歉没有表达清楚。

to Perlvim:
事实证明通过结合Berkeley DB和Perl的substr,我实现了需求。 DB_File 是Berkeley DB的interface。
http://search.cpan.org/~pmqs/DB_File-1.827/DB_File.pm#Opening_a_Berkeley_DB_Database_File
然后,今天所有代码都是通过vim 写的:)

to anyevent:
其实就是花在计算string的长度和截取片段上了。那些短片段多为无用的junk,但是不好舍弃。一般来说,大的片段上才含有完整的基因,我其实想要实现的是,给出一个基因的位置,拿到基因本身,以及其左右一定长度的序列。感谢告知elasticsearch, 我也见过一个有趣的应用,叫tableau. 图像化data的。http://www.tableausoftware.com/products
叶诗文被诬陷时,一帮理科生曾用它来快速反应,http://www.ittc.ku.edu/huanlab/swimData


具体代码:


Step 1. 我利用DB_File module 将整个大表写成文件,代码如下:
  1. #!/usr/bin/perl
  2. #

  3. use strict;
  4. use warnings;
  5. use DB_File;

  6. my %hash;
  7. tie (%hash, "DB_File","wheatA_genome.db") or die "$!\n";

  8. open FILE, "<$ARGV[0]" or die "$!\n";
  9. while(<FILE>){
  10.         chomp;
  11.         my($id,$seq)=split(/\t/,$_);
  12.         $hash{$id}=$seq;
  13. }
  14. close FILE;
复制代码
Step 2. 我在server端写了个perl 的CGI
  1. #!/usr/bin/perl

  2. use strict;
  3. use warnings;
  4. use DBI;
  5. use DB_File;
  6. use CGI qw/param/;


  7. #parameter
  8. my $str=param('q');
  9. my $flank=param('f');


  10. #mysql
  11. my $db = "DBI:mysql:wheat_database:localhost;mysql_socket=/var/lib/mysql/mysql.sock";
  12. my $user_name = "****";
  13. my $password = "****";
  14. my ($dbh,$sth,$scaf,$start,$end,$genome);
  15. my @result;


  16. $dbh=DBI->connect($db,$user_name,$password, {RaiseError => 1});
  17. &mysql($str,"A");
  18. &mysql($str,"D");
  19. $dbh->disconnect();


  20. #header
  21. print "Content-type:text/html\n\n";



  22. my %hash;
  23. tie(%hash,"DB_File","wheat".$genome."_genome.db" ) or print "$!\n";
  24. if(defined $hash{">".$scaf}){
  25.         my $length=length($hash{">".$scaf});
  26.         $start-=($flank+1);
  27.         $end+=$flank;
  28.         if($start <0    ){      $start=0;}
  29.         if($end >=$length){     $end=$length;}
  30.         my $seq_length=$end-$start;
  31.         my $result=substr($hash{">".$scaf},$start,$seq_length);

  32.         print " <textarea name='wheat_scaf_seq' rows='5' cols='120'>";
  33.         print ">$scaf:$start-$end\n$result\n";
  34.         print "</textarea>";

  35. }
  36. else{
  37.         print "<h3>not found!</h3>";
  38. }


  39. sub mysql{
  40.         my ($gene_id,$genome_guess)=@_;
  41.            $sth=$dbh->prepare("SELECT * FROM wheat".$genome_guess."_gene_info WHERE wheat".$genome_guess."_id like '%".$gene_id."%'");
  42.            $sth->execute();
  43.         my @array=$sth->fetchrow_array();
  44.         if (@array >0){
  45.                 $scaf=$array[3];
  46.                 $start=$array[4];
  47.                 $end=$array[5];
  48.                 $genome=$genome_guess;
  49.         }
  50.         $sth->finish();
  51. }

复制代码

参考javascript
  1. function show_wheat_scaf_seq(){


  2.         var str=document.getElementById('q').value;
  3.         var flank=document.getElementById('f').value;


  4.         if (str=="" || flank ==""){
  5.                 document.getElementById("wheat_scaf").innerHTML="";
  6.                 return;
  7.         }

  8.         if (window.XMLHttpRequest){
  9.                 // code for IE7+, Firefox, Chrome, Opera, Safari
  10.                 xmlhttp=new XMLHttpRequest();
  11.         }
  12.         else{
  13.                 // code for IE6, IE5
  14.                 xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  15.         }

  16.         xmlhttp.onreadystatechange=function(){
  17.                 if (xmlhttp.readyState==4 && xmlhttp.status==200){
  18.                         document.getElementById("wheat_scaf").innerHTML=xmlhttp.responseText;
  19.                 }
  20.         }
  21.         xmlhttp.open("GET","wheat_search.pl?q="+str+"&f="+flank,true);
  22.         xmlhttp.send();
  23. }
复制代码

论坛徽章:
0
2 [报告]
发表于 2013-04-30 10:56 来自手机 |只看该作者
如果数据相对固定,可以事先分割大文件成N个小文件,建个索引,根据用户输入,根据索引直接读取数据片段。速度慢不了

论坛徽章:
42
19周年集字徽章-周
日期:2019-10-14 14:35:31平安夜徽章
日期:2015-12-26 00:06:30数据库技术版块每日发帖之星
日期:2015-12-01 06:20:002015亚冠之首尔
日期:2015-11-04 22:25:43IT运维版块每日发帖之星
日期:2015-08-17 06:20:00寅虎
日期:2014-06-04 16:25:27狮子座
日期:2014-05-12 11:00:00辰龙
日期:2013-12-20 17:07:19射手座
日期:2013-10-24 21:01:23CU十二周年纪念徽章
日期:2013-10-24 15:41:34IT运维版块每日发帖之星
日期:2016-01-27 06:20:0015-16赛季CBA联赛之新疆
日期:2016-06-07 14:10:01
3 [报告]
发表于 2013-04-30 14:29 |只看该作者
本帖最后由 laputa73 于 2013-04-30 14:38 编辑

那个48G的电脑可以用吗?

php+ redis

如果并发 不多,只追求速度,可以用一个app实例,用户内存hash也可以




才4G数据,用文件太保守了

论坛徽章:
0
4 [报告]
发表于 2013-04-30 14:44 |只看该作者
mysql百万级的数据绝对没有问题。
我的想法:
1. 建个表,两列: seq, data。seq做索引, 存700万数据。
2. select data from xxx where seq = 'seq1'
3. 对data 取 substring

或者:
1. 建表,两列: id, data.  id用bigint,自增做主键,存700万数据
2. 用storable 以seq作键 id作值,保存一个hash。
3. 用seq找id 用id去mysql找data
4. 对data取substring

论坛徽章:
0
5 [报告]
发表于 2013-04-30 15:00 |只看该作者
你还有个48G内存的机器。。。加个memcache或者php的apc还愁响应慢? 简单点就以seq作键把data存在缓存里就可以吧。

论坛徽章:
0
6 [报告]
发表于 2013-04-30 19:20 |只看该作者
尽量让数据库不做额外的计算,先将客户的长度需求做成索引,用PHP速度慢的话,CGI也快不了。所谓的 Storable and BerkeleyDB的查询机制,都不如 mysql, 除非做成内存数据库。

论坛徽章:
0
7 [报告]
发表于 2013-04-30 20:20 |只看该作者
Perlvim 发表于 2013-04-30 19:20
尽量让数据库不做额外的计算,先将客户的长度需求做成索引,用PHP速度慢的话,CGI也快不了。所谓的 Storabl ...

这说的就太不对了
BerkeleyDB怎么可能查询速度比MySQL慢?这就像说C++比C快一样。早期的MySQL都是用BerkeleyDB实现的,关系型数据库的优势是事务,并发,和一些特定情况下的查询,关系型数据库是永远不会有BerkeleyDB这种以排序二叉树的实现快

楼主应该考虑一下你用1分多钟时间是花在哪了?实在不明白就看看执行计划。700万的数据你用什么数据库,只要加个索引,怎么都不应该是1分钟,但你的要在1M的字符串上定位一个片段,时间有可能花在这上了

我的意思是,你要先清除你这1分钟是花在哪了,再用相应技术改进现有算法。我觉得你可以考虑搜索引擎的原理,用文件索引,对应的产品可以看看ElasticSearch

论坛徽章:
1
程序设计版块每日发帖之星
日期:2015-10-07 06:20:00
8 [报告]
发表于 2013-05-01 09:12 |只看该作者
回复 2# iamlimeng


    谢谢关注,问题已经搞定。详见修改后的原帖。

论坛徽章:
1
程序设计版块每日发帖之星
日期:2015-10-07 06:20:00
9 [报告]
发表于 2013-05-01 09:13 |只看该作者
回复 3# laputa73


     谢谢关注,问题已经搞定。详见修改后的原帖。

论坛徽章:
1
程序设计版块每日发帖之星
日期:2015-10-07 06:20:00
10 [报告]
发表于 2013-05-01 09:14 |只看该作者
回复 4# soul20040103


     谢谢关注,问题已经搞定。详见修改后的原帖。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP