MYSQL网页编程之怎样进步MySQL查询效力?
平台即服务PaaS、基础设施即服务IaaS、软件即服务SaaS都是我们比较熟悉的MySQL学习教程,现在又出现了数据库即服务DBaaS,以基于云的方式存储结构化数据。mysql|sql|效力|查询MySQL因为它自己的玲珑和操纵的高效,在数据库使用中愈来愈多的被接纳.我在开辟一个P2P使用的时分已经利用MySQL来保留P2P节点,因为P2P的使用中,结点数动辄上万个,并且节点变更频仍,因而必定要坚持查询和拔出的高效.以下是我在利用过程当中做的进步效力的三个无效的实验.l利用statement举行绑定查询利用statement能够提早构建查询语法树,在查询时不再必要构建语法树就间接查询.因而能够很好的进步查询的效力.这个办法合适于查询前提流动但查询十分频仍的场所.利用办法是:[*]绑定,创立一个MYSQL_STMT变量,与对应的查询字符串绑定,字符串中的问号代表要传进的变量,每一个问号都必需指定一个变量.
[*]查询,输出每一个指定的变量,传进MYSQL_STMT变量用可用的毗连句柄实行.
代码以下://1.绑定boolCDBManager::BindInsertStmt(MYSQL*connecthandle){//作拔出操纵的绑定MYSQL_BINDinsertbind;if(m_stInsertParam==NULL)m_stInsertParam=newCHostCacheTable;m_stInsertStmt=mysql_stmt_init(connecthandle);//构建绑定字符串charinsertSQL;strcpy(insertSQL,"insertintoHostCache(SessionID,ChannelID,ISPType,""ExternalIP,ExternalPort,InternalIP,InternalPort)""values(?,?,?,?,?,?,?)");mysql_stmt_prepare(m_stInsertStmt,insertSQL,strlen(insertSQL));intparam_count=mysql_stmt_param_count(m_stInsertStmt);if(param_count!=FEILD_NUM)returnfalse;//添补bind布局数组,m_sInsertParam是这个statement联系关系的布局变量memset(insertbind,0,sizeof(insertbind));insertbind.buffer_type=MYSQL_TYPE_STRING;insertbind.buffer_length=ID_LENGTH/*-1*/;insertbind.buffer=(char*)m_stInsertParam->sessionid;insertbind.is_null=0;insertbind.length=0;insertbind.buffer_type=MYSQL_TYPE_STRING;insertbind.buffer_length=ID_LENGTH/*-1*/;insertbind.buffer=(char*)m_stInsertParam->channelid;insertbind.is_null=0;insertbind.length=0;insertbind.buffer_type=MYSQL_TYPE_TINY;insertbind.buffer=(char*)&m_stInsertParam->ISPtype;insertbind.is_null=0;insertbind.length=0;insertbind.buffer_type=MYSQL_TYPE_LONG;insertbind.buffer=(char*)&m_stInsertParam->externalIP;insertbind.is_null=0;insertbind.length=0;insertbind.buffer_type=MYSQL_TYPE_SHORT;insertbind.buffer=(char*)&m_stInsertParam->externalPort;insertbind.is_null=0;insertbind.length=0;insertbind.buffer_type=MYSQL_TYPE_LONG;insertbind.buffer=(char*)&m_stInsertParam->internalIP;insertbind.is_null=0;insertbind.length=0;insertbind.buffer_type=MYSQL_TYPE_SHORT;insertbind.buffer=(char*)&m_stInsertParam->internalPort;insertbind.is_null=0;insertbind.is_null=0;//绑定if(mysql_stmt_bind_param(m_stInsertStmt,insertbind))returnfalse;returntrue;}//2.查询boolCDBManager::InsertHostCache2(MYSQL*connecthandle,char*sessionid,char*channelid,intISPtype,unsignedinteIP,unsignedshorteport,unsignedintiIP,unsignedshortiport){//添补布局变量m_sInsertParamstrcpy(m_stInsertParam->sessionid,sessionid);strcpy(m_stInsertParam->channelid,channelid);m_stInsertParam->ISPtype=ISPtype;m_stInsertParam->externalIP=eIP;m_stInsertParam->externalPort=eport;m_stInsertParam->internalIP=iIP;m_stInsertParam->internalPort=iport;//实行statement,功能瓶颈处if(mysql_stmt_execute(m_stInsertStmt))returnfalse;returntrue;}l随机的猎取纪录在某些数据库的使用中,我们并非要猎取一切的满意前提的纪录,而只是要随机选择出满意前提的纪录.这类情形罕见于数据营业的统计剖析,从年夜容量数据库中猎取小量的数据的场所.有两种办法能够做到1.惯例办法,起首查询出一切满意前提的纪录,然后随机的选择出部分纪录.这类办法在满意前提的纪录数良多时效果不睬想.2.利用limit语法,先猎取满意前提的纪录条数,然后在sql查询语句中到场limit来限定只查询满意请求的一段纪录.这类办法固然要查询两次,可是在数据量年夜时反而对照高效.示例代码以下://1.惯例的办法//功能瓶颈,10万笔记录时,实行查询140ms,猎取了局集500ms,其他可疏忽intCDBManager::QueryHostCache(MYSQL*connecthandle,char*channelid,intISPtype,CDBManager::CHostCacheTable*&hostcache){charselectSQL;memset(selectSQL,0,sizeof(selectSQL));sprintf(selectSQL,"select*fromHostCachewhereChannelID=%sandISPtype=%d",channelid,ISPtype);if(mysql_real_query(connecthandle,selectSQL,strlen(selectSQL))!=0)//检索return0;//猎取了局集m_pResultSet=mysql_store_result(connecthandle);if(!m_pResultSet)//猎取了局集堕落return0;intiAllNumRows=(int)(mysql_num_rows(m_pResultSet));///<一切的搜刮了局数//盘算待前往的了局数intiReturnNumRows=(iAllNumRows<=RETURN_QUERY_HOST_NUM)?iAllNumRows:RETURN_QUERY_HOST_NUM;if(iReturnNumRows<=RETURN_QUERY_HOST_NUM){//猎取逐笔记录for(inti=0;i<iReturnNumRows;i++){//猎取逐一字段m_Row=mysql_fetch_row(m_pResultSet);if(m_Row!=NULL)strcpy(hostcache.sessionid,m_Row);if(m_Row!=NULL)strcpy(hostcache.channelid,m_Row);if(m_Row!=NULL)hostcache.ISPtype=atoi(m_Row);if(m_Row!=NULL)hostcache.externalIP=atoi(m_Row);if(m_Row!=NULL)hostcache.externalPort=atoi(m_Row);if(m_Row!=NULL)hostcache.internalIP=atoi(m_Row);if(m_Row!=NULL)hostcache.internalPort=atoi(m_Row);}}else{//随机的选择指定笔记录前往intiRemainder=iAllNumRows%iReturnNumRows;///<余数intiQuotient=iAllNumRows/iReturnNumRows;///<商intiStartIndex=rand()%(iRemainder+1);///<入手下手下标//猎取逐笔记录for(intiSelectedIndex=0;iSelectedIndex<iReturnNumRows;iSelectedIndex++){mysql_data_seek(m_pResultSet,iStartIndex+iQuotient*iSelectedIndex);m_Row=mysql_fetch_row(m_pResultSet);if(m_Row!=NULL)strcpy(hostcache.sessionid,m_Row);if(m_Row!=NULL)strcpy(hostcache.channelid,m_Row);if(m_Row!=NULL)hostcache.ISPtype=atoi(m_Row);if(m_Row!=NULL)hostcache.externalIP=atoi(m_Row);if(m_Row!=NULL)hostcache.externalPort=atoi(m_Row);if(m_Row!=NULL)hostcache.internalIP=atoi(m_Row);if(m_Row!=NULL)hostcache.internalPort=atoi(m_Row);}}//开释了局集内容mysql_free_result(m_pResultSet);returniReturnNumRows;}//2.利用limit版intCDBManager::QueryHostCache(MYSQL*connecthandle,char*channelid,unsignedintmyexternalip,intISPtype,CHostCacheTable*hostcache){//起首猎取满意了局的纪录条数,再利用limit随机选择指定笔记录前往MYSQL_ROWrow;MYSQL_RES*pResultSet;charselectSQL;memset(selectSQL,0,sizeof(selectSQL));sprintf(selectSQL,"selectcount(*)fromHostCachewhereChannelID=%sandISPtype=%d",channelid,ISPtype);if(mysql_real_query(connecthandle,selectSQL,strlen(selectSQL))!=0)//检索return0;pResultSet=mysql_store_result(connecthandle);if(!pResultSet)return0;row=mysql_fetch_row(pResultSet);intiAllNumRows=atoi(row);mysql_free_result(pResultSet);//盘算待取纪录的高低局限intiLimitLower=(iAllNumRows<=RETURN_QUERY_HOST_NUM)?0:(rand()%(iAllNumRows-RETURN_QUERY_HOST_NUM));intiLimitUpper=(iAllNumRows<=RETURN_QUERY_HOST_NUM)?iAllNumRows:(iLimitLower+RETURN_QUERY_HOST_NUM);//盘算待前往的了局数intiReturnNumRows=(iAllNumRows<=RETURN_QUERY_HOST_NUM)?iAllNumRows:RETURN_QUERY_HOST_NUM;//利用limit作查询sprintf(selectSQL,"selectSessionID,ExternalIP,ExternalPort,InternalIP,InternalPort""fromHostCachewhereChannelID=%sandISPtype=%dlimit%d,%d",channelid,ISPtype,iLimitLower,iLimitUpper);if(mysql_real_query(connecthandle,selectSQL,strlen(selectSQL))!=0)//检索return0;pResultSet=mysql_store_result(connecthandle);if(!pResultSet)return0;//猎取逐笔记录for(inti=0;i<iReturnNumRows;i++){//猎取逐一字段row=mysql_fetch_row(pResultSet);if(row!=NULL)strcpy(hostcache.sessionid,row);if(row!=NULL)hostcache.externalIP=atoi(row);if(row!=NULL)hostcache.externalPort=atoi(row);if(row!=NULL)hostcache.internalIP=atoi(row);if(row!=NULL)hostcache.internalPort=atoi(row);}//开释了局集内容mysql_free_result(pResultSet);returniReturnNumRows;}l利用毗连池办理毗连.在有大批节点会见的数据库计划中,常常要利用到毗连池来办理一切的毗连.一样平常办法是:创建两个毗连句柄行列,余暇的守候利用的行列和正在利用的行列.当要查询时先从余暇行列中猎取一个句柄,拔出到正在利用的行列,再用这个句柄做数据库操纵,终了后必定要从利用行列中删除,再拔出到余暇行列.计划代码以下://界说句柄行列typedefstd::list<MYSQL*>CONNECTION_HANDLE_LIST;typedefstd::list<MYSQL*>::iteratorCONNECTION_HANDLE_LIST_IT;//毗连数据库的参数布局classCDBParameter{public:char*host;///<主机名char*user;///<用户名char*password;///<暗码char*database;///<数据库名unsignedintport;///<端口,通常是0constchar*unix_socket;///<套接字,通常是NULLunsignedintclient_flag;///<通常是0};//创立两个行列CONNECTION_HANDLE_LISTm_lsBusyList;///<正在利用的毗连句柄CONNECTION_HANDLE_LISTm_lsIdleList;///<未利用的毗连句柄//一切的毗连句柄先连上数据库,到场到余暇行列中,守候利用.boolCDBManager::Connect(char*host/*="localhost"*/,char*user/*="chenmin"*/,char*password/*="chenmin"*/,char*database/*="HostCache"*/){CDBParameter*lpDBParam=newCDBParameter();lpDBParam->host=host;lpDBParam->user=user;lpDBParam->password=password;lpDBParam->database=database;lpDBParam->port=0;lpDBParam->unix_socket=NULL;lpDBParam->client_flag=0;try{//毗连for(intindex=0;index<CONNECTION_NUM;index++){MYSQL*pConnectHandle=mysql_init((MYSQL*)0);//初始化毗连句柄if(!mysql_real_connect(pConnectHandle,lpDBParam->host,lpDBParam->user,lpDBParam->password,lpDBParam->database,lpDBParam->port,lpDBParam->unix_socket,lpDBParam->client_fla))returnfalse;//到场到余暇行列中m_lsIdleList.push_back(pConnectHandle);}}catch(...){returnfalse;}returntrue;}//提取一个余暇句柄供利用MYSQL*CDBManager::GetIdleConnectHandle(){MYSQL*pConnectHandle=NULL;m_ListMutex.acquire();if(m_lsIdleList.size()){pConnectHandle=m_lsIdleList.front();m_lsIdleList.pop_front();m_lsBusyList.push_back(pConnectHandle);}else//特别情形,闲行列中为空,前往为空{pConnectHandle=0;}m_ListMutex.release();returnpConnectHandle;}//从利用行列中开释一个利用终了的句柄,拔出到余暇行列voidCDBManager::SetIdleConnectHandle(MYSQL*connecthandle){m_ListMutex.acquire();m_lsBusyList.remove(connecthandle);m_lsIdleList.push_back(connecthandle);m_ListMutex.release();}//利用示例,起首猎取余暇句柄,使用这个句柄做真实的操纵,然后再插回到余暇行列boolCDBManager::DeleteHostCacheBySessionID(char*sessionid){MYSQL*pConnectHandle=GetIdleConnectHandle();if(!pConnectHandle)return0;boolbRet=DeleteHostCacheBySessionID(pConnectHandle,sessionid);SetIdleConnectHandle(pConnectHandle);returnbRet;}//传进余暇的句柄,做真实的删除操纵boolCDBManager::DeleteHostCacheBySessionID(MYSQL*connecthandle,char*sessionid){chardeleteSQL;memset(deleteSQL,0,sizeof(deleteSQL));sprintf(deleteSQL,"deletefromHostCachewhereSessionID=%s",sessionid);if(mysql_query(connecthandle,deleteSQL)!=0)//删除returnfalse;returntrue;}尽管MySQL也有一个认证培训项目,但是它的培训却要比Oracle或MS-SQL相差很远。尽管有的使用MySQL的用户表示,MySQL很容易上手,但是对于具有企业级数据库需求的用户来说, 是否碎片会引发效率问题?这都是需要进一步探讨的东西。varbinary(max)代替image也让SQLServer的字段类型更加简洁统一。 原理很简单,对要求长时间计算某一时间点的报表生成和防用户操作错误很有帮助。但是比起Oracle10g的闪回技术还是细粒度不够。可惜! 如安全管理、备份恢复、性能监控和调优等,SQL只要熟悉基本操作就可以,只要程序设计部分只要稍加了解即可(如存储过程、触发器等)。 这一点很好的加强了profiler的功能。但是提到profiler提醒大家注意一点。windows2003要安装sp1补丁才能启动profiler。否则点击没有反应。 大家注意一点。如下面的例子: 这一点很好的加强了profiler的功能。但是提到profiler提醒大家注意一点。windows2003要安装sp1补丁才能启动profiler。否则点击没有反应。 对于微软系列的东西除了一遍遍尝试还真没有太好的办法
页:
[1]