现在的位置: 首页 > 综合 > 正文

一种基于内存的快速查询的解决方案。

2012年04月12日 ⁄ 综合 ⁄ 共 7281字 ⁄ 字号 评论关闭

 转载请注明出处(http://www.cnblogs.com/goldentime,作者:黄金年代。文章虽差也属原创,苍蝇虽小也是块肉!)

被网上小将们骂怕了。但是该写还是要写,而且坚持原创继续毁人不倦。我们的口号是(没有蛀牙!!!)

本垃圾文章描述了一种类似于缓存的查询方式,将数据放入内存中进行查询,从而达到提高响应速度增加吞吐量的目的。方法简单,属于原创。缺点等待大家来评论。

本文技术内容其实很简单,但是我前边会写一些技术之外的东西,因为不仅在中国就是在世界上很多东西比技术更重要。毕竟技术是为了更好的提供服务。往往是最末的一环,请各位程序员和准程序员清醒这一点。另外还简单介绍了设计的过程欢迎有同样小型项目管理经验的同道评论,也给初学者参考。

正文开始:

之前我们参考了南方兄弟招办已有系统(运行过一年,我们本来想去年搞,但是没搞起来,人家先做了)地运行情况。算是学习了经验。最后我们认为整个系统的压力应当集中在填报志愿过程中(废话)。

填报方案选型过程:

一、如果考生直接选择院校名称和专业的话,对服务器和网络压力太大,该方案淘汰。(在后期征集志愿时由于院校数目少可以考虑)

二、志愿翻译:简单说来就是:考生输入报考院校的学校代号和专业代号,然后系统翻译为现实的名称,考生检查是否正确即可。

例如100030102 翻译为:清华大学:工程力学与航天航空工程,艺术设计学。

选择:方案二,考生填写代码,系统翻译志愿。

设计实现过程

设计目标:

翻译过程很简单但是主要是次数比较多。每位考生一次填写正确需要翻译9批次*2-5院校*1院校名称+6专业名称=250次左右的翻译。共55万考生。一共需要翻译1.25亿次。平均到2天的工作时间16小时,平均每秒翻译2170次。再用正态分布估算。我们觉得每秒1万次翻译作为设计目标应当能够满足实际应用的情况。

说起来简单,实际上每个学校翻译的时候还需要判断科类、考生类别、限报条件等,所以sql查询语句效率不会太高。

翻译方案选型:

一、Sql存储过程

已有系统的查询使用存储过程来完成查询,将web服务器和数据库服务器之间的通信减到最小。然后通过对数据库进行优化将性能最大化。

这种方法比较成熟,也是大家首先能够想到的,实施起来风险也较小,数据流量也可很容易的分布到多个数据库上(不要给我提什么群集,挖掘一类的,我们有2F5,根本不需要那么麻烦再烂的系统也能够运行的差不多。但是不能那样做事。第一设备再先进,也要你的底层架构设计合理才可以。第二、设备技术再先进是人家微软、IBM的又不是自己的,要想进步,要自己去努力。我实在不明白为什么有些人使用起那些名词来那么理直气壮好像是自己发明的一般。)

为了规避风险我们首先实现了该方法,但是并没有在数据优化时下功夫因为我们认为,这种方法效率不高。比如:我们仅仅是只读的查询。一共的3万记录进行1.25亿次查询相当于每条平均查重复4000多次,这是巨大的性能浪费。

而且sql查询时作负载均衡我们嫌麻烦,我们这时就是想要试验去做一种没有试过的高效的内存查询算法。看看到底能要出多少性能来

二、专有数据库查询:实际上无论是平易近人的mssql还是走下神坛的ORCAL由于太大,求全涉及到方方面面。他的数据查询效率并不如专有数据库效率高。就像CE不如PALM快,虽然PALM不先进但是运行快。但是时间长了,由于CE的通用性和兼容性还是占据了比较大的市场。

但是专有的数据库用起来一方面技术比较冷门,另外我们没有时间去进行评估也就无法去选择。单独为一个系统去学习一个冷门数据库不划算。

三、内存数据库,目前内存数据库上网查了查有一个韩国的厂商在工控领域做的不错。另外好像微软的Microsoft SQL Server 2005 Compact Edition

(这个不确认是内存的,但是好像支持,而且好像对多用户支持不好或不支持)做的也不错。感兴趣的去这个地址:http://www.microsoft.com/downloads/details.aspx?FamilyId=E6BC81E8-175B-46EA-86A0-C9DACAA84C85&displaylang=en#filelist

四、私有算法。我们最后选择了自动开发一种查询算法。因为:

1、 创新的需求。做东西技术人员总要有所追求创新,有个东西是你自己的,总是用别人的有啥意思?

2、 我们的查询比较简单,没有必要实现到数据库的层次。为了我们简单的查询,没有必要去实现Codd十二法则?这样我们就可以借着这个项目研究新技术,同时还可以控制风险。

3、 时间充裕:我们设计完之后,用2天就实现了基于内存查询的并进行了评估(虽然网上没有现成的,但是只要想到了确实很简单,就和原来我们写汉字字库实际上一样),结论是值得一试。

具体实现:(请注意本文的实现与现实严格关联,因为实际工作中这些政策年年变,不可能复用,所以也就没有完全面向对象,而只是抽了出来做成类方便维护而已。)

系统具体实现部分

系统实现的原理:

原理很简单将数据放入数组或哈希表中,然后查找即可,关键是如何实现。

关键在于:

第一、       如何将表放入内存中。

第二、       如何对外提供查询。

对于第一个问题我们可以很简单的通过将数组和哈希定义为静态变量从而常驻内存。

请原谅我的代码中有拼音因为。。。教育部的表就是拼音缩写的,因为广大招办有很多老同志,都换成英文不可能。

 public static string[,] stryxs = new string[32004];//前边是学校数,后边是每组结构 学校名称+kldm+pc+zsfw 科类代码、批次、招生范围
  public static Hashtable htzys = new Hashtable();

  然后在构造函数中填充数据例如:

///首先加载院校代码表
        jihuas dsjihua = new jihuas();
        jihuasTableAdapters.tjhyxTableAdapter jhapt 
= new jihuasTableAdapters.tjhyxTableAdapter();        
        
//将指定院校(YXBM从01开始排)放入数组
        foreach(jihuas.tjhyxRow dr in dsjihua.tjhyx)
        
{
//填充数据
    }

然后在全局文件Global.asax中将该类实例化即可

 void Application_Start(object sender, EventArgs e) 
    
{
        
// 在应用程序启动时运行的代码        
        cache ap = new cache();//加载全局类
    }

对于第二个问题,就好说多了,有了数据,查询、就是了。。

好了不说废话,看程序。。

系统代码实现:

///本模块功能是:
///1、构建全局缓存,在全局缓存中构建键列,供志愿查找使用
///2、提供刷新全局缓存功能。(调用构造函数)
///构建全局缓存,应用一次构造函数即可
///提供的全局缓存包括
///1、志愿:院校、专业名称
///2、区域对照表:地市、县区、报名点代码对照表

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections;
using System.Text;
using System.Text.RegularExpressions;


/// <summary>
/// cachetest 的摘要说明
/// </summary>

public class cache
{
   
//str??? 代表字符串数组 ht???代表哈希表 
    
//public static ArrayList alyxs=new ArrayList ();//测试中使用过的方式
public static string[,] stryxs = new string[32004];
///前边是学校数,后边是每组结构 学校名称+kldm+pc+zsfw共4项, 
///其中学校编码为从0001开始的4位编码,正好作为数组的下表stryxs[1]=0001院校的数据

    public static Hashtable htzys = new Hashtable();///志愿表
    public static Hashtable htdishi = new Hashtable();///地市
    public static Hashtable htxq = new Hashtable();///县区
    public static Hashtable htbmd = new Hashtable();///报名点
    
/// <summary>
    
/// 构造函数,加载缓存
    
/// </summary>

    public cache()
    
{
        
///首先加载院校代码表
        jihuas dsjihua = new jihuas();
        jihuasTableAdapters.tjhyxTableAdapter jhapt 
= new jihuasTableAdapters.tjhyxTableAdapter();
        jhapt.Fill(dsjihua.tjhyx);
        
///没有0院校,需要处理一下
        stryxs[00= "院校填写错误";
        stryxs[
01= "";        
        
//将指定院校(YXBM从01开始排)放入数组
        foreach(jihuas.tjhyxRow dr in dsjihua.tjhyx)
        
{
      
int yxbm = Convert.ToInt16(dr.YXBM);
            
///07年有一个院校 编号为9001,将其转化为3199,后来临时加的,
            
///各部门没有协调好以至于编号从9001开始,其实要是使用3200以内闲置的代码号就不用这样处理了
            
///再有新增的也这样处理。

            if (yxbm == 9001)
            
{
                yxbm 
= 3199;
            }

            stryxs[yxbm, 
0= dr.YXMC.Trim();
            
//累加该院校的kldm
            
//此处没有判断科类是否会重复,不需要判断,重复不影响例如AABBCCDD,只要有即可。此处可以改用STRINGBULIDER,
            string kldm = stryxs[yxbm, 1];
            
string newkldm=dr.KLDM.Trim();
            kldm 
= kldm + newkldm;
            stryxs[yxbm, 
1= kldm;

            
//累加该院校的pc省略
            
//记录招生范围省略
        }

       
        
//加载专业代码表
        ///SELECT DISTINCT yxbm, yxmc, jhxz, kldm, pc, cc
        
///ORDER BY yxbm

        jihuasTableAdapters.tjhzyTableAdapter zyapt = new jihuasTableAdapters.tjhzyTableAdapter();
        zyapt.Fill(dsjihua.tjhzy);
        
foreach (jihuas.tjhzyRow dr in dsjihua.tjhzy)
        
{
            
///追加的hash表格式为 keys  专业名称
            
///其中keys 为 yxbm+ZYBM+kldm+pc
            
///使用keys查找 

            htzys.Add(dr.YXBM.Trim() + dr.ZYBM.Trim()+dr.KLDM.Trim()+dr.PC.Trim(), dr.ZYMC);            
        }

        
///SELECT YXBM, ZYBM, zymc, jhxz, KLDM, pc, cc 
        
///ORDER BY jhxz, KLDM, pc, cc, YXBM, ZYBM


        
//加载报名点代码
        jihuasTableAdapters.baomingdianTableAdapter bmdapt = new jihuasTableAdapters.baomingdianTableAdapter();
        bmdapt.Fill(dsjihua.baomingdian);
        
foreach (jihuas.baomingdianRow dr in dsjihua.baomingdian)
        
{
            
///追加的hash表格式为 keys  报名点名称
            
///其中keys 为 dmddm

            htbmd.Add(dr.ZXDM.ToString().Substring(1,6), dr.ZXMC.ToString().Trim());
        }


        
//加载区县代码
        jihuasTableAdapters.td_xqdmTableAdapter xqdapt = new jihuasTableAdapters.td_xqdmTableAdapter();
        xqdapt.Fill(dsjihua.td_xqdm);
        
foreach (jihuas.td_xqdmRow dr in dsjihua.td_xqdm)
        
{
            
///追加的hash表格式为 keys  县区名称
            
///其中keys 为 xqdm

            htxq.Add(dr.xqdm.ToString().Substring(1,4), dr.xqmc.ToString().Trim());
        }


        
//加载地市代码
        jihuasTableAdapters.td_dsdmTableAdapter dsdapt = new jihuasTableAdapters.td_dsdmTableAdapter();
        dsdapt.Fill(dsjihua.td_dsdm);
        
foreach (jihuas.td_dsdmRow dr in dsjihua.td_dsdm)
        
{
            
///追加的hash表格式为 keys  地市名称
            
///其中keys 为 dsdm

            htdishi.Add(dr.dsdm.ToString().Substring(12), dr.dsmc.ToString().Trim());
        }
        
    }

    
//将数据表读入缓存中。然后使用
    /// <summary>
    
/// 志愿转换
    
/// </summary>
    
/// <param name="zyxx">志愿信息</param>
    
/// 序号     0       1       2       3       4       5       6          7       8        9       10      11      12          13          14          15              16
    
/// 有效     yxdh    zydh1   zydh2   zydh3   zydh4   zydh5   zydh6      tj     laiyuan      ksh     pcdm    zyh     zyhanyi     tiaoji      validstr     bmddm          kldm
    
/// <returns></returns>

    public static string tranzhiyuan(ArrayList zyxx)
    

抱歉!评论已关闭.