并行查询让SQL Server加速运行

并行查询让SQL Server加速运行,第1张

并行查询其优势就是可以通过多个线程来处理查询作业 从而提高查询的效率 SQL Server数据库为具有多个CPU的数据库服务器提供并行查询的功能 以优化查询作业的性能 也就是说 只要数据库服务器有多个CPU 则数据库系统就可以使用多个 *** 作系统进程并行执行查询 *** 作 来加速完成查询作业

一 并行查询三步走

并行查询作业在数据库中 主要经过三个步骤

首先 数据库会判断是否需要进行并行查询 在数据库中有一个查询优化器 会对SQL语句进行优化 然后数据库才会去执行查询语句 而这个查询器在对SQL语句进行查询优化时 其中一个动作就是判断是否需要对SQL语句进行查询优化 也就是说 并不是所有的SQL查询语句都可以从并行查询中获取收益 如果查询优化器认为查询语句可以从并行查询中获取收益的话 则就会将交换运算符插入到查询执行计划中 为并行查询做准备 故哪些语句需要采用并行查询 哪些不需要 这不用数据库管理员关心 数据库查询优化器会帮管理员作出这个决定 数据库管理员需要清楚的是 在哪些情况下 数据库SQL优化器会认为不宜采用并行查询 通常情况下 只要满足以下条件的任何一个 则就不会执行并行查询 一是对于特定的查询 查询优化器认为串行查询执行计划要快于任何可能的并行执行计划;二是查询的串行执行成本并不高 不需要进行并行查询;三是查询中包含无法并行运行的标量运算符或者关系运算符 若从数据库管理员的角度讲 第三个条件对我们具有最大的影响 当数据库预计未来可能利用并行查询来提高数据库性能时 则在数据库设计时 就需要注意避免使用那些无法在并行查询功能中使用的运算符 因为某些关系运算符或者逻辑运算符可能会要求查询计划一定要在串行模式中进行 或者部分需要在串行模式下进行 如此的话 查询优化器就不会利用并行查询功能来提高查询语句的性能 这是数据库管理员在数据库设计时必须要考虑到的一个细节问题

其次 确定并行的进程数 当查询优化器在查询语句中插入交叉运算符之后 数据库就会执行并行查询 并行查询在执行计划时可以使用多个线程 此时 就又遇到了一个问题 数据库会把这个查询作业分成几个进程 *** 作呢此时 数据库管理员就需要知道上什么叫做并行度 其实 在处理并行查询的时候 数据需要知道最大可使用的进程与实际使用的进程 而最大可使用的进程就叫做并行度 这个并行度的值是在服务器级别中进行设置 也可以通过系统存储过程来进行修改 但是 最大可使用进程数不一定等于实际是用进程数 实际是用进程数是数据库在查询计划执行时初始化的时候确定的 也就是说 这不用数据库管理员去额外的设定 数据库系统会自动根据计划的复杂程度来确定合理的进程数目 当然其实际采用的进程数不能够超过并行度 即最大可以使用的进程数

最后执行查询 当以上内容确定好之后 数据库就会执行具体的查询语句 在这一步中 需要注意一个问题 数据库管理员还可以在查询语句中指定MAXDOP查询提示来修改这个进度值 也就是说 如果某个查询作业数据库管理员认为可能会耗时比较久 就可以为这个查询作业设置比较大的进度值 当利用MAXDOP查询提示设置这个并行进度值之后 它会覆盖预先设置的默认值 从而实现针对单个查询语句设置额外的进度值 以提高某些特殊查询作业的性能

二 并行查询中需要注意的内容

注意点一 需要注意硬件方面的限制

并行查询是数据库提高查询性能的一个有力举措 不过其往往受到比较大的约束 如上面提高的一些基于成本考虑之外 还有一些硬性的限制 如通常情况下 只有在数据库服务器有多个微处理器(CPU )的情况下数据库才会考虑执行并行查询 也就是受 只有具有多个CPU的计算机才能够使用并行查询 这是一个硬性的限制条件 另外在查询计划执行过程中 数据库还会判断当时是否有足够多的线程可以使用 每个查询 *** 作都要求一定的线程数才能够执行;而且执行并行计划比执行串行计划需要更多的线程 所需要的线程数也会随着并行度的提高而提高 如果在并行计划执行的时候 当时数据库服务器没有足够的线程让并行计划使用的话 数据库引擎就会自动减少并行度 甚至会放弃并行查询而改为串行计划 所以说 数据库是否能够执行并行查询 要受到其硬件的限制 为此 如果企业真的需要通过并行查询来提高数据库性能的话 则管理员就需要根据情况来调整硬件配置

注意点二 不建议对所有查询都使用并行查询

通常情况下 笔者认为最好只对大型表的连接查询 大量数据的聚合 *** 作 大型结果集的重复排序等等 *** 作才应用并行查询的功能 如果在这些 *** 作上执行并行查询的话 那么其改善数据库性能的效果是非常明显的 相反 如果对于简单查询执行并行查询的话 可能执行并行查询所需要的额外协调工作会大于其潜在的性能提升 所以 数据库管理员在确定是否需要执行并行查询功能的话 需要慎重 笔者的建议是 在数据库服务器级别上 最好不要设置并行查询 即把并行度设置为 或者一个比较小的值 然后对于一些特殊的查询 *** 作 利用MAXDOP查询提示来设置最大的可使用进程数 如此的话 可能会更加的合理 如果有时候数据库管理员不知道是否需要采用并行查询功能的话 则可以通过数据库自带的统计功能进行判断 为了区别并行查询计划到底有没有从并行查询中受益 数据库引擎可以将执行查询的估计开销与并行查询的开销阀值进行比较 并行计划只有对需时较长的查询通常更加有益;因为其性能优势将抵消初始化 同步和终止并行计划所需的额外时间开销

注意点三 数据库会根据查询所涉及到的行数来判断是否要并行查询

上面谈到 最好对大型表的连接查询 大量数据的聚合 *** 作 大型结果集的重复排序等等 *** 作才应用并行查询的功能 因为只有如此 并行查询带来的收益才会超过其付出的代价 但是 并不是说连接查询 聚合 *** 作 排序等作业都适合采用并行查询 当数据库在考虑并行查询计划的时候 查询优化器还会去确定所涉及到的行数 如果所涉及到的行数台少 则将不会考虑执行并行查询计划 而会采用串行方式执行查询语句 如此的话 可以避免因为启动 分发 协调的开销大大超过并行执行作业所带来的收益 这本来是一个不错的设计 但是也会给数据库管理员带来一定的麻烦 如现在数据库管理员想要测试并行查询到底可以在多大程度上影响查询 *** 作 就有点麻烦 因为其有数据量的限制 如果数据库管理员需要进行这个测试 还不得不先在数据库系统中导入足够多的数据才行 这就限制了数据库管理员的测试 *** 作 不过话说回来 这个机制仍然是不错的 因为数据库管理员不用去考虑 当数据库规模到多大的时候采用并行查询

注意点四 同一个 *** 作在不同时候会采用不同的进程数

lishixinzhi/Article/program/SQLServer/201311/22469

vc 线程处理方法内查询mysql数据库会有多次连接失败

/线程函数

UINT Thread1(LPVOID lpParam)

{

while()//循环access记录

{

mysql_real_connect(&myCont//连接mysql

mysql_close(&myCont);//关闭连接

}

return 0;

}

1、线程内注册与连接数据库的竞争问题

文档上对多线程下数据库应用的注意事项写的很简明,一个线程创建的 QSqlDatabase 对象和 查出来的 QSqlQuery 对象只能给本线程用(注意,是对象,不是数据库连接本身,连接本身用名字可以多线程使用),其他情况是“不支持的”。在一个需要有几个线程并发访问不同数据库的应用中,我首先试图在各个线程的起始分别以不同的名称调用 addDatabase / database 、open,但是程序偶然会崩溃,跟踪后发现,虽然Qt 声称很多方法是“线程安全”的,但是几个方法串起来,就出问题了。Qt 会动态的加载数据库的plugin, 加载 plug in 的部分,涉及到对本地库文件的管理,这一部分,出现了竞争。于是,很自然的想到在初始连接部分设置 Mutex 保护,从 addDatabase / database到 open 的部分,要保证其原子性,问题再也没有出现。

2、数据库连接意外断裂后,恢复连接的问题

在MFC 中,一旦中途TCP连接断裂,直接重新 Open 就可以了。在Qt 里,这一招不好使了。即便 调用了 close ,再次open 也是不行的。处理方法:

在检测到问题出现后,关闭连接,并 removeDatabase; 而后,不要立刻 addDatabase, 反而是要回到该连接所在的事件循环。没有详细跟源码,很可能在 removeDatabase 后的事件循环中,Qt 内部做了一些释放 *** 作。 怎么办呢, 可以设置一个恢复定时器,比如 1分钟,重新 addDatabase,就可以啦。如果心急的话,直接显式调用processEvent() 方法强制循环。

在多线程下,注意1中的问题,需要 Mutex保护。

3、数据库插件的依赖性问题

在 Windows 下,有时我们的机器上按了好几个 Qt 版本,PATH里索性神马也不设置,依赖开发环境的继承环境适应不同的版本。这有两个问题。一是发布程序的时候,数据库驱动依赖的dll 也要与可执行文件在同一路径下发布。比如 mysql 的 dll, PostgreSQL 的依赖等。二是在集成开发环境中,这些依赖也要位于执行档文件夹下。否则,会造成虽然可以枚举到可用驱动,但是死活连接不上。调试一下就知道,原来是在路径中找不到依赖项,导致dll加载失败哦!

以mysql来说,可能出现脏读、不可重复读以及幻读,mysql默认设置是可重复读,即一次事务中不会读取到不同的数据。

可以做如下 *** 作:

1)打开两个客户端,均设置为RR;

2)在一个事务中,查询某个 *** 作查到某份数据;比如是某个字段version=1存在数据;

3)在另一个事务中,删除这份version=1的数据;删除后,在2所属的事务中查询数据是没有变化的,还是存在version=1的数据;

4)当我们在2所属的事务中继续更新数据,那么会发现更新不了,明明我们就看到了这份version=1的数据;

缓存一致性:

缓存一致,与什么一致?是与数据库一致,对外查询每个时刻一致;所以在针对于缓存与数据库之间该先更新哪一个呢?可能有人觉得我先更新数据库,再更新缓存不就行了吗?但是有想过个问题吗?

当用户已经支付成功了,更新到数据库,但是呢?你还在缓存中显示未支付,在用户点击频率很高并且数据库压力过大,来不及同步到缓存时,那你是不是很尴尬,这就是典型的不一致了。此时用户再支付,那你又告诉他已经支付了,那他会把你骂死的

那该怎么来做呢?我们可以这样,先更新缓存再更新数据库,那么存在什么问题呢?

1)缓存更新成功,但是数据库更新失败,而被其它的并发线程访问到

2)缓存淘汰成功,但是数据库更新失败,这也会引发后期数据不一致

//将数据库中的数据条数分段 public void division(){ //获取要导入的总的数据条数 String sql3="SELECT count() FROM [CMD][dbo][mycopy1]"; try { pss=consprepareStatement(sql3); rss=pssexecuteQuery(); while(rssnext()){ Systemoutprintln("总记录条数:"+rssgetInt(1)); sum=rssgetInt(1); } //每30000条记录作为一个分割点 if(sum>=30000){ n=sum/30000; residue=sum%30000; }else{ residue=sum; } Systemoutprintln(n+" "+residue); } catch (SQLException e) { // TODO Auto-generated catch block eprintStackTrace(); } }线程类public MyThread(int start,int end) { thisend=end; thisstart=start; Systemoutprintln("处理掉余数"); try { Systemoutprintln("--------"+ThreadcurrentThread()getName()+"------------"); ClassforName(SQLSERVERDRIVER); Systemoutprintln("加载sqlserver驱动"); cons = DriverManagergetConnection(CONTENTS,UNS,UPS); stas = conscreateStatement(); Systemoutprintln("连接SQLServer数据库成功!!"); Systemoutprintln("加载mysql驱动"); ClassforName(MYSQLDRIVER); con = DriverManagergetConnection(CONTENT,UN,UP); sta = concreateStatement(); // 关闭事务自动提交 consetAutoCommit(false); Systemoutprintln("连接mysql数据库成功!!"); } catch (Exception e) { eprintStackTrace(); } // TODO Auto-generated constructor stub } public ArrayList<Member> getAll(){ Member member; String sql1="select from (select row_number() over (order by pmcode) as rowNum," + " from [CMD][dbo][mycopy1]) as t where rowNum between "+start+" and "+end; try { Systemoutprintln("正在获取数据"); allmembers=new ArrayList(); rss=stasexecuteQuery(sql1); while(rssnext()){ member=new Member(); membersetAddress1(rssgetString("address1")); membersetBnpoints(rssgetString("bnpoints")); membersetDbno(rssgetString("dbno")); membersetExpiry(rssgetString("expiry")); membersetHispoints(rssgetString("hispoints")); membersetKypoints(rssgetString("kypoints")); membersetLevels(rssgetString("levels")); membersetNames(rssgetString("names")); membersetPmcode(rssgetString("pmcode")); membersetRemark(rssgetString("remark")); membersetSex(rssgetString("sex")); membersetTelephone(rssgetString("telephone")); membersetWxno(rssgetString("wxno")); membersetPmdate(rssgetString("pmdate")); allmembersadd(member); // Systemoutprintln(membergetNames()); } Systemoutprintln("成功获取sqlserver数据库数据!"); return allmembers; } catch (SQLException e) { // TODO Auto-generated catch block Systemoutprintln("获取sqlserver数据库数据发送异常!"); eprintStackTrace(); } try { rssclose(); stasclose(); } catch (SQLException e) { // TODO Auto-generated catch block eprintStackTrace(); } return null; } public void inputAll(ArrayList<Member> allmembers){ Systemoutprintln("开始向mysql中写入"); String sql2="insert into testmycopy2 values (,,,,,,,,,,,,,)"; try { ps=conprepareStatement(sql2); Systemoutprintln("-------------------------等待写入数据条数: "+allmemberssize()); for(int i=0;i<allmemberssize();i++){ pssetString(1, allmembersget(i)getPmcode()); pssetString(2, allmembersget(i)getNames()); //Systemoutprintln(allmembersget(i)getNames()); pssetString(3, allmembersget(i)getSex()); pssetString(4, allmembersget(i)getTelephone()); pssetString(5, allmembersget(i)getAddress1()); pssetString(6, allmembersget(i)getPmdate()); pssetString(7, allmembersget(i)getExpiry()); pssetString(8, allmembersget(i)getLevels()); pssetString(9, allmembersget(i)getDbno()); pssetString(10, allmembersget(i)getHispoints()); pssetString(11, allmembersget(i)getBnpoints()); pssetString(12, allmembersget(i)getKypoints()); pssetString(13, allmembersget(i)getWxno()); pssetString(14, allmembersget(i)getRemark()); //插入命令列表 //psaddBatch(); psexecuteUpdate(); } //psexecuteBatch(); concommit(); psclose(); conclose(); thisflag=false; Systemoutprintln(ThreadcurrentThread()getName()+"--->OK"); } catch (SQLException e) { // TODO Auto-generated catch block Systemoutprintln("向mysql中更新数据时发生异常!"); eprintStackTrace(); } } @Override public void run() { // TODO Auto-generated method stub while(true&&flag){ thisinputAll(getAll()); } }

以上就是关于并行查询让SQL Server加速运行全部的内容,包括:并行查询让SQL Server加速运行、vc 线程处理方法内查询mysql数据库会有什么、QT多线程查询数据库显示到tablewidget里面等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/9856200.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-02
下一篇 2023-05-02

发表评论

登录后才能评论

评论列表(0条)

保存