关系经济人类预测化学自然
中准网
自然科学
知识物理
化学生物
地理解释
预测理解
本质社会
人类现象
行为研究
经济政治
心理结构
关系指导
人文遗产

云贝教育技术文章内存闩锁分析

5月25日 亡命徒投稿
  作者:刘晓峰
  原文链接:http:www。tdpub。cnBlogdetailid1304。htmlLatch通用数据结构
  讲解闩锁前我们先讲一个数据结构,也就是散列表(hashtable),下图为拉链法表示的散列表
  这里不用关注散列表如何实现。我们关注其特性给定key,传入到hash函数,返回value代表其内存地址,所以查询非常快如果不同的key值,返回相同的内存地址,表示发生了hash碰撞,碰撞的key值存储在上图的链表中链表的首段挂在一个数组后面,数组里存放的hash函数的value,链表里存放的是keyKey的多少决定了数组的大小,如果固定数组大小,新写入一个key,如果发生碰撞,则需要维护链表,插入到链表的尾端。
  讲完这个散列表,跟我们的闩锁有什么关系呢。
  简单回顾一下oracle解析步骤
  1。加载到共享池SQL源代码被加载到RAM中进行解析。(硬解析步骤)
  2。语法分析Oracle分析语法以检查拼写错误的SQL关键字。
  3。语义解析Oracle验证字典中的所有表和列名称,并检查您是否有权查看数据。
  4。查询转换Oracle将把复杂的SQL转换为更简单、等效的形式,并酌情用物化视图替换聚合。在Oracle的早期版本中,必须为实体化视图重写设置queryrewritetrue参数。
  5。优化Oracle然后根据您的模式统计信息(或者可能来自10g中的动态采样的统计信息)创建一个执行计划。Oracle在此期间构建成本决策树,选择感知成本最低的路径。
  6。创建可执行文件Oracle使用本机文件调用构建可执行文件以服务SQL查询。
  7。获取行Oracle然后执行对数据文件的本地调用以检索行并将它们传递回调用程序。
  当载入一条SQL文本的时候,如果库缓存中存在此SQL文本,表示是软解析,跳过上面的步骤1,如果库缓存中不存在,则表示是硬解析。
  上面的步骤涉及到存在和不存在,所以是一个find问题。此时hash表这个数据结构就有了用武之地。
  上图演化为:
  Librarycache:库缓存
  Librarycachelatch,库缓存闩锁。
  为什么需要这个闩锁呢。其实就是问共享池内存数据为什么需要被保护。也就是为什么内存数据会涉及到DML,如果是只读的,且不修改任何属性,也就不存在问题。
  我们知道共享池用于缓存执行计划,数据字典缓存,SQL结果集和函数缓存,而缓存是有大小的,那些使用次数最少的缓存会从内存中老化退出。也就是针对上图的hashtable,链表中的数据会被清除掉,而新的缓存又不断加入进来,所以这个链表会动态变化,修改链表的next值等于next的next的时候(其实是双向链表,所以还有last),如果这时还有会话去访问此链表,那么就会有问题。相当于读的时候,不能写,写的时候不能读。这不就是共享锁和排它锁吗?
  但是Oracle的锁(lock),是用于保护磁盘数据,如果要处理高速内存数据,机制太慢,我们需要一个轻量级的内存锁闩(lacth),要求获取和释放时间都极短,去保护内存的数据。Lock最主要是需要排队,而latch谁在一个时间片内抢到了就算谁的。
  锁和闩分别对应视图vlock和vlatch。除此之外我们还有互斥锁,pin锁,DDL锁,自定义锁。我们的hashtable的数组上,每一个桶都有一个互斥锁(如果是保护lock的latch,则每个桶上还会有latch锁,比如enqueuehashchains),而pin锁会锁链表上的每一个节点。比如链表节点存储了执行计划,为了防止你正在使用执行计划EXECUTESQL的时候,系统把此节点从链表删除。
  我们主要关注桶前面的librarycachelatch锁
  Latch分类
  1。愿意等待:如果获取不到闩,会话休眠,然后再次尝试。休眠时间称之为latchfreewaittime。librarycachelatches主要是愿意等待模式
  2。立即:如果当前进程获取不到闩,转而获取另一个闩,直到所有闩的都获取失败。Latch视图分析
  查询vlatch有如下字段
  Addr地址
  latch等于vlatchchildren。LATCH
  level级别
  name闩锁名称
  hash等于vlatchchildren。HASH
  gets当前进程以愿意等待模式成功获取到闩锁的次数,如果闩自旋了1千次,才最终获取到闩锁,gets1而不是1001,
  misses当前进程以愿意等待模式尝试获取闩锁,当第一次尝试获取就失败了,则missed1,并开始自旋
  sleeps进程以愿意等待模式尝试获取闩锁,第一次获取失败,然后自旋,几千次循环都没成获取,则开始睡眠,sleeps1。
  immediategets进程以立即模式获取闩锁,第一次尝试获取就获取成功,则immediategets1
  immediatemisses立即模式获取失败
  waiterswoken
  waitsholdinglatch
  spingets进程以愿意等待模式尝试获取闩锁,首次获取失败,然后开始自旋。如果在自旋里成功获取闩锁,spingets1
  waittime进程总等待时间,单位一般为微秒
  参数增加顺序:
  missesspingets自旋也没获取到sleeps
  正常情况missesspingetssleeps
  获取闩锁的顺序
  1。成功获取,然后释放
  2。获取失败自旋自旋超过spincount,开始从CPU调度出去,开始休眠休眠完毕唤醒,继续获取(1获取又失败misses1,自旋睡眠时间上升)(2成功获取gets1,然后释放)
  为什么要自旋?
  任务调度出CPU又调度回来涉及到上下文切换,而正常情况下闩锁获取释放速度很快,所以我在循环里一直获取,正常情况下循环几次就获取到了,如果循环个几千次,还是获取不到,才开始睡眠。这样平均等待时间比前者(指获取不到就开始睡眠)要快很多。
  进程调度出CPU需要切换上下文,耗时较长,所以循环获取监测latch:librarycache
  因为这个库缓存闩锁比较少见,因此不去分析latch视图了,我们后面详细分析快块缓冲区闩锁现象,下面给出监测方法:这些SQL和会话都是有问题的
  查询等待事件SELECTsid,serial,osuser,programFROMvsessionWHEREsidIN(SELECTblockingsessionFROMvsessionWHEREeventlatch:librarycache);
  查询高子游标计数和高版本sqlSELECTDISTINCTsqlidFROMvsqlplanWHEREchildnumber300SELECTsqlid,versioncount,sqltextFROMvsqlareaWHEREversioncount300;
  查询高绑定变量sqlSELECTAVG(bindcount)avgnumbindsFROM(SELECTsqlid,COUNT()bindcountFROMvsqlbindcaptureWHEREchildnumber0GROUPBYsqlid);SELECTFROM(SELECTsqlid,COUNT()bindcountFROMvsqlbindcaptureWHEREchildnumber0GROUPBYsqlid)HAVINGbindcount300
  再次讨论latch:cachebufferschains
  分析这个词
  Latch:闩锁
  Cache:缓存,比如从磁盘读入数据,放入缓存,下一次直接读缓存而不是磁盘
  buffers:缓冲区,比如有写缓冲区,写满了之后,再统一将缓冲区写磁盘,
  chains:链
  当我们遇到cachebuffers就知道是块缓冲区缓存,而不是库缓存粒度
  下图是块缓冲区的各个缓冲池示意图
  来源:https:codeantenna。comadBDXzPb3zQ
  我们先接触一个词,granule(粒度),BLOCK是数据库最小IO单元,那么granule就是共享池最小分配进程的连续虚拟内存单元,也是访问数据的最小工作单元。比如我们的自动内存管理,共享池和块缓冲区的大小会动态调整,那么增减的单元就是granule。查询vsgaresizeops可以看到最近的调整结果
  上图可以看到:
  一个缓冲池有多个granule,granule内部分为《缓冲区头部数组》和《缓冲区链》,一个工作集可以跨多个granule。这里《缓冲区头部数组》其实就是我们之前看到的XBH
  查询粒度大小,我本地是4MselectfromvsgainfowherenameGranuleS
  查询共享池和块缓冲区大小SELECTs。component,s。currentsize10241024currentsize,s。granulesize10241024granulesizeFROMvsgadynamiccomponentssWHEREs。componentin(DEFAULTbuffercache,sharedpool)COMPONENTCURRENTSIZEGRANULESIZE1sharedpool24042DEFAULTbuffercache284
  可以看到共享池240M,60个粒度,块缓冲区默认池28M,也就是7个粒度
  查询块缓冲区粒度的链表SELECTge。grantype,ct。component,ge。granprev,ge。grannum,grannextFROMxksmgege,xkmgsctctWHEREge。grantype!6ANDct。grantypege。grantypeandct。componentDEFAULTbuffercacheGRANTYPECOMPONENTGRANPREVGRANNUMGRANNEXT19DEFAULTbuffercache0636429DEFAULTbuffercache63646539DEFAULTbuffercache64656649DEFAULTbuffercache65666759DEFAULTbuffercache66676869DEFAULTbuffercache67686979DEFAULTbuffercache68690
  GRANNEXT指向下一个粒度的指针,GRANNUM是当前指针,从上图可以看到按顺序排列,所以可以得出结论,我的块缓冲区没有动态调整过,当然因为我启用的是手动SGA内存管理。缓冲池内的所有的GRANULE双向链表串联起来组成大的缓冲池。
  查询所有内存组件的粒度SELECTct。component,COUNT(1)4FROMxksmgege,xkmgsctctWHERE11ANDct。grantypege。grantypeGROUPBYct。component
  查询当前大小SELECTs。component,s。currentsize10241024currentsize,s。granulesize10241024granulesizeFROMvsgadynamiccomponentssWHEREs。componentin(DEFAULTbuffercache,sharedpool)
  查询当前块缓冲区详细信息
  LRU
  我们的缓冲池里面的缓冲区个数是固定的,缓冲区链由工作集管理,当新的数据进入内存的时候,如何决定哪些缓冲区需要clear,LRU(Leastrecentlyused)算法就是最近最少被使用缓冲区应该被老化退出。
  回到我们的工作集SELECTk。cnumset工作集中缓存区数量,k。setlatchcachebufferlatch地址,k。cnumrepl缓冲区数量总和,k。nxtrepl最多使用的缓冲区,缓冲区链的热端(链表头部),k。prvrepl最少使用的缓冲区,缓冲区链的冷端(链表尾部),k。coldhd缓冲区头部链表冷热分界点,K。NXTREPLAX备用链头部,备用链比主链少了刷新脏块,获取和释放pin,所以从备用链获取可老化的缓冲区比主链更快一般而言,备用链头部链接在k。prvrepl对应的主链的尾部,K。PRVREPLAX备用链尾部,k。addr等于xbh。setds表示此工作集有多少缓冲区FROM
  我们只关注主链,这个表的每一行就是一个工作集,由链表头部nxtrepl和链表尾部prvrepl决定的链表就是缓冲区头部链表,那么此链表的每一个节点就是代表一个个缓冲区。
  缓冲区头部可以简单理解成缓冲区的指针,所以后面遇到缓冲区还是缓冲区头部,可以理解他们都是指代同一个东西,就是缓冲区。每个缓冲区内部里面有很多block。
  上面的链表就是cachebufferlruchain链表,每一个缓冲区上有一个TCH接触计数,这个TCH的修改机制比较复杂,这里不详细描述,所以我们简化一下,可以简单看成,链表左边的TCH较高,越往右越低,温度较低的缓冲区是从内存老化的优先选择对象。
  (TCH计算逻辑并不是访问一次就1,这里不详细讨论,只是大概表达意思)
  而我们下面要讲到的cachebufferchain,虽然节点还是一样的,都是缓冲区,不过他们能链接到一个链表上完全是因为hash散列的结果,所以这个cachebufferchain链上的温度排列并不是左边的最高,右边的越低
  Latch锁
  现在我们有了一个LRU链表,决定哪些缓冲区需要老化,但是我们还需要前面讲到的hashtable结构去快速判断是物理读还是逻辑读。回想我们通过索引访问数据的过程,通过where条件对应的索引树,找到叶子节点对应的ROWID,ROWID是文件号,块号,块内行号组成的伪列,所以拿到ROWID就确定了是哪一个块,此次我们需要使用hashtable,还是以上图举例
  这里的key值简单等价为块号,传入的桶对应的链表就是缓冲区,也就是上图链表中的矩形节点。我们顺序读,读入一个BLOCK,然后通过散列函数,计算出它应该放入那个桶中,然后按某种规则加入到缓冲区链表中。
  举例:
  现在我们传入磁盘block号,通过hashtable得到了桶1,那么接下来应该选择放入桶1的三个缓冲区中的一个,具体选择哪一个就是上一节讲到的LRU链,现在我们把LRU链也画一下,假设我们有2个工作集
  颜色越淡,表示越冷,因此备选缓冲区是2,我们需要修改缓冲区2的数据,回顾我们的库缓存latch,修改前必须要对其加锁,所以改造一下我们的缓冲区hash链
  我们必须首先获取桶1和桶2对应的latch1,然后再去修改桶1的缓冲区链表,这个latch就是标题的latch:cachebufferschains既然是我们熟悉的latch锁,回想一下
  Misses,spingets,sleeps这些关键词,一旦我们有两个SQL访问的块位于同一个latch管辖的桶内,这两个SQL又都在大量进行buffergets,他们都会争抢latch锁,最后造成此等待事件。
  此时我们假如获取到了latch1,同时通过LRU链我们选择把数据放在缓冲区2中,先pin住缓冲区2,如果不能pin住,则需要等待,此时触发等待事件bufferbusywats成功获取pin之后释放闩锁,再缓存我们的数据(这里都不考虑一致性读情况),然后获取闩锁,解除pin,再解除latch锁,完成访问。(LRU链也发生了更新,所以LRU上也会有LATCH锁去控制,这里不详细讨论)
  重现latch:cachebufferschains
  很多文章讲到这个等待事件,给出的解决方案是解决热点块现象,比如多个会话访问同一个块,不过热点块并不是决定因素,同一个bufferchain上的块多会话频繁访问才会出现。而bufferbusywait,才与热点块关系比较紧密。热点块以及块上TCH过高,只是说有可能有关系,我们现在来重现一下。
  首先随便在latch链中找到一行数据(如果oracle能提供函数,传入块信息,返回latch信息,那么我就能自己造测试数据了)SELECTaddrFROMvlatchchildrenWHERENAMEcachebufferschainsANDrownum1;
  然后查一下这个bufferheader链上都有哪些块的数据SELECTe。owner。e。segmentnamesegmentname,e。fileid,e。extentidextent,x。dbablk,x。dbablke。blockid1block,x。tch,l。child,l。gets,l。misses,l。sleeps,l。waittime10000003600,l。latch,l。hashFROMvlatchchildrenl,xbhx,dbaextentseWHERE11ANDl。addr000000006BDE6660ANDe。fileidx。fileANDx。hladdrl。addrANDx。dbablkBETWEENe。blockidANDe。blockide。blocks1ORDERBYx。tchDESC;
  第一行块号是1,因此简单查询第一行就行(反复执行此SQL你会发现TCH会持续增长)selectfromSYS。AQSUBSCRIBERLWMwhererownum1;
  第二行是一个聚簇,与索引聚簇表有关,第4行是一个索引,这里我们没有函数去查询索引块对应的数据是哪一行,第三行是一个表,因此用第三行对应的表测试。selectfromdbaextentsdwhered。fileid1andd。extentid20;
  查询此表分配了128个块
  尝试从blockid118528开始,找3个块,一直访问此数据,但是并没有增加接触计数SELECTROWID,dbmsrowid。rowidblocknumber(ROWID)FROMsys。optstatsnapshotsWHEREdbmsrowid。rowidblocknumber(ROWID)1185283ANDdbmsrowid。rowidblocknumber(ROWID)1185280;
  因此直接按ROWID排序,取前1000行数据selectfrom(selectfromsys。optstatsnapshotorderbyrowid)whererownum1000;
  因此改造这两个SQL,期望重现latch锁等待事件
  窗口1:SELECTuserenv(sid)FROM470declarecursoracurisselectfromSYS。AQSUBSCRIBERLWMwhererownum1;beginforiin1。。1000000
  窗口2:SELECTuserenv(sid)FROM467declarecursoracurisselectfrom(selectfromsys。optstatsnapshotorderbyrowid)whererownum1000;beginforiin1。。10000
  执行后查看等待事件表SELECTFROMvsessionwaitsWHEREs。sidIN(467,470)
  成功重现latch:cachebufferschains
  查看此p1的值,并不是我们上图取出来的000000006BDE6660
  如果我们代入000000006BDA63D0会发现出现的段是其它两个系统段,
  而且按我们期望,取消467的查询,却并不能缓解470上的latch锁现象
  当我反复执行上面的查询时候,我发现接触计数高的是这两个段
  SYS。AQSUBSCRIBERLWM和SYS。COBJ,只能说这两个对象不能独立访问,因此我们去实际环境中重现此等待事件。
  1。找到一个latch锁,其中包含表数据SELECTl。addr,e。owner。e。segmentnameFROMvlatchchildrenl,xbhx,dbaextentseWHERE11ANDe。fileidx。fileANDx。hladdrl。addrANDx。dbablkBETWEENe。blockidANDe。blockide。blocks1ANDe。segmenttypeTABLEANDe。tablespacenameSYSTEM
  2。随便取一个latch,将此latch地址传入SELECTe。owner。e。segmentname,segmentname,l。addr,e。extentidextent,x。dbablk,x。dbablke。blockid1block,x。tch,l。child,l。gets,l。misses,l。sleeps,l。waittime10000003600,l。latch,l。hashFROMvlatchchildrenl,xbhx,dbaextentseWHEREl。addrin(0000001934656D68)ANDe。fileidx。fileANDx。hladdrl。addrANDx。dbablkBETWEENe。blockidANDe。blockide。blocks1
  SEGMENTNAM
  DBABLK
  MTLSYSTEMITEMSB
  3219221hrPOREQUISITIONLINESAL
  1738115hr3通过块号找到缓存的ROWIDSELECTROWID,dbmsrowid。rowidblocknumber(ROWID)FROMMTLSYSTEMITEMSBsWHEREdbmsrowid。rowidblocknumber(ROWID)3219221;SELECTROWID,dbmsrowid。rowidblocknumber(ROWID)FROMPOREQUISITIONLINESALLsWHEREdbmsrowid。rowidblocknumber(ROWID)1738115
  4。开两个窗口循环取数2266DECLARECURSORacurISSELECTFROMporequisitionlinesallmsiWHEREROWIDIN(AAAdlDAIbAAGoWDAAA,AAAdlDAIbAAGoWDAAB,AAAdlDAIbAAGoWDAAD,AAAdlDAIbAAGoWDAAC,AAAdlDAIbAAGoWDAAG,AAAdlDAIbAAGoWDAAF,AAAdlDAIbAAGoWDAAE,AAAdlDAIbAAGoWDAAI,AAAdlDAIbAAGoWDAAH,AAAdlDAIbAAGoWDAAK,AAAdlDAIbAAGoWDAAJ,AAAdlDAIbAAGoWDAAM,AAAdlDAIbAAGoWDAAL);BEGINforiin1。。100000loopFORarecINacurLOOPNULL;ENDLOOP;END;4045DECLARECURSORacurISSELECTFROMmtlsystemitemsbmsiWHEREROWIDIN(AAQ54NAKNAAMR8VAAA,AAQ54NAKNAAMR8VAAC,AAQ54NAKNAAMR8VAAE,AAQ54NAKNAAMR8VAAG,AAQ54NAKNAAMR8VAAI,AAQ54NAKNAAMR8VAAK,AAQ54NAKNAAMR8VAAM,AAQ54NAKNAAMR8VAAO);BEGINFORiIN1。。100000LOOPFORarecINacurLOOPNULL;ENDLOOP;ENDLOOP;END;
  5。查询等待事件selectfromvsessionwaitswheres。sidin(4045,2266);
  SID
  EVENT
  P1RAW
  2266hrlatch:sharedpool
  60292678hr4045hrlatch:sharedpool
  602922B8
  没测试出来块缓冲区上的latch锁,却测试出来latch:sharedpool
  共享池闩锁的争用是由于共享池容量不足、未共享SQL或数据字典的大量使用,
  查询硬解析selectfromVSESSTIMEMODELswheres。SIDin(4045,2266)
  硬解析花费时间并不严重,所以这个等待事件可能是我第一次装载此SQL,同时绑定变量过多导致,再次重复执行
  SID
  EVENT
  P1
  2266hrSQLNetmessagefromclient
  1952673792hr4045hrlatchfree
  107898301512hr出现了latchfree,这个包括了所有的闩锁现象,如果我们对此会话开启了跟踪,并打开原始trace文件,搜索latchfree
  搜索此number号selectfromvlatchnamelwherel。latch228LATCHNAMEDISPLAYNAMEHASHCONID1228cachebufferschainscachebufferschains35633055850
  就显示为实际的latch锁。
  根据我们前面的判断,如果停掉2266会话的查询,而是单独查询4045,则不会出现跟buffercache有关的闩锁,此时我们重新按12345的步骤测试一下,唯一的区别是不执行2266的查询,等待事件结果如下:
  SID
  EVENT
  P1
  2266hrSQLNetmessagefromclient
  1952673792hr4045hrSQLNetmessagefromclient
  1952673792hr符合我们的预测
  如何解决latch锁导致的等待问题
  回顾一下它的原理,我们有多个进程正在访问同一个buffercachechain上的缓冲区,一个获取到了,另一个就不得不等待。所以核心就是减少额外的buffergets。
  如何减少:
  1。避免循环中重复读取相同的块,而且循环本身速度较快的话,闩锁现象越严重
  2。检查索引效率,避免出现索引全扫描或者大段的索引范围扫描,本不需要扫描额外的buffer,由于糟糕的索引或者执行计划,额外扫描了这些block
  3。避免全表扫描,不过oracle有机制控制,读大表的时候会避免更新TCH,我们期望这些大表不会污染我们的块缓冲区(可以放入回收池),一趟全表扫描并不可怕,因为我们的等待来源于逻辑读,全表扫描第一次全是物理读
  如果你不能减小buffergets,也就是说就是要这么频繁访问,那么第二步就是直接路径读,直接路径读不在赘述
  如果你也不能采用直接路径读,那么我们只能从降低争用入手
  1。如果争用发生在同一个块的不同行,尝试使用反向键,防止同时访问同一个块
  2。因为latch散列只与块属性有关,所以你要么分时间段执行这两个SQL,要么增大块缓冲区,并期望能散列到别的latch上。
  3。由2可知,对争用比较严重的段采用createasselect,期望生成新的BLOCKID并散列到不同的LATCH上(未测试)
投诉 评论 转载

云贝教育技术文章内存闩锁分析作者:刘晓峰原文链接:http:www。tdpub。cnBlogdetailid1304。htmlLatch通用数据结构讲解闩锁前我们先讲一个数据结构,也就是散列表……律师格林伍德商业损失或达百万他必须通过足球让生活重回正轨直播吧2月8日讯大曼彻斯特警方在上周撤销了对曼联球星格林伍德强奸和袭击等全部刑事指控,但格林伍德未来职业生涯目前仍不明朗。体育法律专家大卫维尼在接受《太阳报》采访时表示,这次事……郭艾伦小试牛刀,杨鸣赛场失控,同曦结束连败,篮协再闹笑话辽宁和青岛的二番战不出意料的激烈,郭艾伦也终于憋不住地复出了,纵观全场,辽宁队真的不能没有郭艾伦,他的作用绝不是数据上的体现,有了他,韩德君都可以安心打替补了,杨鸣的暴怒虽有些……所见所得,都很科学探究饮食领域的科学知识我们日常生活中的饮食习惯与饮食选择,都离不开科学知识和原理。本文将从营养成分、饮食标准以及健康饮食等方面进行探究,并建议大家在日常饮食生活中去了解并运用这些科学知识。一、……英雄联盟手游,无限火力最适合的英雄不管是端游还是手游这些英雄都是比较适合玩无限火力模式的。探险家EZ,正常模式下该英雄的Q技能算是所有英雄里冷却最高的技能,而且还拥有不俗的伤害。无限火力模式就更不用说了,再加上……朝鲜美女计划在中国旅游一周,可是待了3天就想回国,为什么呢?朝鲜美女计划在中国旅游一周,可是待了3天就想回国,为什么呢?每年都有很多的中国人计划去朝鲜旅游,殊不知在朝鲜,也有很多人计划去中国旅游,只不过相比之下,朝鲜人……19年过去了,当年那个冒死一举的唐功红,如今怎么样了?2004年雅女子举重的决赛场上。172。5公斤的成功举起,让韩国代表团集体陷入了兴奋中。他们一个个好像看到了回国后高官厚禄、风光无限的场面。这时候一位中国选手……青岛这个森林公园有知道的吗?青岛有个森林公园火了很多小姐姐去拍照打卡中式园林风、绿植满园你知道这里吗?很多人和小编一样,以为这真的是个公园,其实这里是一个新楼盘的售楼处展示区。……价格战越打越凶!上汽不再遮遮掩掩,直接掀桌子,我来当卷王最近,价格战伤不起,引发了业内的广泛关注与讨论。进入4月份,价格战的浪潮却丝毫没有减弱,谁也没有想到上汽旗下的飞凡新能源汽车突然变脸,在这样的大环境下,同样不甘示弱,也加入了这……泰国最有名的十大特色美食,第九道看着像黑暗料理,实则特别好吃说起泰国,不知道你对这个国家了解多少?众所周知泰国的人妖特别出名,实际上更出名的是泰国的佛教文化,泰拳也是发源于泰国。那去泰国都有哪些特产可以捎带呢?那就是天然乳胶枕头了,因为……万顺叫车靠谱吗?万顺叫车融合线上线下发展,逐步实现新目标智能出行正在成为网约车甚至是整个交通运输业态的全新趋势,目前的网约车平台基本将专注力投放到线上技术、运营当中。而在万顺叫车,线上互联网技术的发展至关重要,同理,线下实体店的发展……外媒中芯国际赌对了在芯片制造领域,台积电可谓是独占一档,无论是芯片产能,还是芯片良品率,都远超三星和英特尔。虽然三星3nm制程工艺领先台积电一步实现了量产,但是由于产能和良品率不高,至今也……
今日大暑,身清心静暑自消田亮女儿森蝶成功晋级,赢得开门红,他们没有选择进入娱乐圈神经网络与传统统计方法的简单对比王者荣耀元歌皮肤设计大赛正式开始知识分享神装助阵,做游戏赢家,ROG电竞显示器燃爆2021核聚变电玩1岁女童被喂成脑瘤!这款婴儿用品,你可能天天都在给娃用中国股市芯片概念核心龙头股一览!(名单)报告称索尼PS5游戏机明年出货量将达3000万台深圳机场加快一流基础设施打造全年共开工建设16个项目迪拜回国遥遥无期,啥时候可以买到机票?王长伟十二月三日农历十一月初十思故乡叶县常村的山
火星星座看你占有欲有多强刘德华帮弟弟成为富豪,亲姐却穷困潦倒,他却说绝不帮她除夕夜的日记400字心理技巧:如何找回真实的自己?怎样自制洗银水三种方式自制洗银水都是生活常见用品伏羲造句用伏羲造句大全FQ是什么意思FQ的解释最多能举多长时间趋势分析(碳中和政策现状与趋势分析)半路夫妻没有结婚证财产怎么分割北京用大数据锁定35万人筛查病毒?谣言年元旦可以搬新房吗

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找菏泽德阳山西湖州宝鸡上海茂名内江三亚信阳长春北海西安安徽黄石烟台沧州湛江肇庆鹤壁六安韶关成都钦州