精华内容
下载资源
问答
  • 光电探测器频率响应

    2021-01-19 20:16:44
    光电探测器正常工作所能探测到... 在半导体光电探测器中,影响响应速度的因素主要有[12]:  (1)耗尽区内载流子的渡越时间。当耗尽区内的电场达到饱和时,载流子以漂移速率Vs运动,设定耗尽区宽度饿。  (2)
  • 实际应用中,电子电路所处理的信号几乎都不是简单的...★ 频率失真:对不同频率的信号响应不同而造成的失真,不产生新的频率分量。 由于放大电路中存在电抗元件(如管子的极间电容,电路的负载电容、分布电容、耦合电容

    实际应用中,电子电路所处理的信号几乎都不是简单的单一频率信号,它们的幅度及相位通常都由固定比例关系的多频率分量组合而成,且具有一定的频谱。

    放大电路对不同频率信号的幅值放大不同。这样的失真称其为幅度失真

    放大电路对不同频率信号产生的相移不同,表现为时间延时不同。这样的失真称其为相位失真

    在这里插入图片描述
    ★ 非线性失真:信号进入器件的非线性区域,会产生新的频率分量。

    ★ 频率失真:对不同频率的信号响应不同而造成的失真,不产生新的频率分量。

    由于放大电路中存在电抗元件(如管子的极间电容,电路的负载电容、分布电容、耦合电容、射极旁路电容等),当信号频率较高或较低时,不但放大倍数会变小,而且会产生超前或滞后的相移,使得放大电路对不同频率信号分量的放大倍数和相移都不同。所以当放大电路静态工作点合适 ,且处于放大区的时候还会产生失真。

    放大电路的放大倍数是信号频率的函数,称之为频率响应频率特性

    放大电路中存在电抗性元件 耦合电容、旁路电容、变压器等

    在这里插入图片描述
    此时在看固定偏置共射放大电路,在前面中频段时,一直把电容C1 认为是理想元件对直流开路、对交流短路,但如果考虑频率对电抗的影响,当频率由底变高时(小于100Hz),电抗是由高变低的明显变化,当频率较低时,此时电抗较大在几百欧姆,通过观察电容和输入电路的关系就可以发现,此时电容C1 的电抗就和 rbe 是相当的,因此必将对输入回路的信号传输产生较大的影响,不能视其为短路;只有当信号频率较高时(大于100Hz以上),由于电抗的急剧减小,才能忽略对其输入回路的影响,视其为短路

    正是耦合电容的电抗对频率的敏感使得放大电路的传输也会受到频率的影响。当放大电路传输低频信号的时候,由于C1 电抗的影响,必然会对整个放大电路的放大性能带来影响。当频率降低时,C1 的电抗将会增大,就会使得晶体管的输入电流 ib 减小。 ib 的减小必会导致 ic 的减小。因此使得输出电压 Uo 在面对同样的信号源 Us 的时候,也会出现一个衰减,就会使得整个放大电路的前级放大倍数 Aus 下降。所以由于耦合电容 C1 的存在,使得放大电路在低频段将会增益的损失。

    晶体管的极间电容

    在这里插入图片描述
    晶体管的集电结和发射极都存在电容效应,电容的直接体现就是跨接在集电结和发射结的结电容,由于结电容的容量并不大,所以在信号低频的时候可以认为他的电抗非常大,视其为开路,不会对信号传输带来影响。

    随着信号频率逐渐升高,晶体管极间电容和分布电容、寄生电容等杂散电容的容抗减小,对信号的传输带来较大的影响。

    因此晶体管的结电容将会放大电路的高频响应产生较大影响 ,由于极间电容的存在使得放大电路在高频段的增益也会出现损失

    同时在之前一直用于中低频信号分析的 h 参数等效模型,由于没有考虑结电容的影响,因此将不再适用于高频段的电路分析,此时必须采用一个考虑结电容的高频小信号模型进行分析,所以当研究电路的高频响应时,三极管的低频小信号模型不再适用,而要采用高频小信号模型

    电路中客观存在着各类电抗器件是影响电路频率响应的主要因素

    当低频时,主要是耦合电容起作用,而晶体管的结电容可视为理想的开路
    当高频时,主要是晶体管结电容起作用,而耦合电容可视其为短路
    由于耦合电容和结电容的影响,使得放大电路的放大倍数在低频和高频都会产生损失;

    频率响应是衡量放大电路对不同频率输入信号适应能力的一项技术指标

    频率响应(频率特性)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mpxFnBtW-1610457215617)(F:\模拟电子技术\截图\12频率响应\12-2频率响应幅频特性.png)]

    利用图形化的方式描述放大电路的幅频特性和相频特性,下图就是一个放大电路的幅频特性和相频特性,通过对他定性的观察,就可以发现这样一个放大电路在低频段和高频段增益都出现了损失,和之前对耦合电容以及晶体管的结电容对增益的影响的结论是相符合的。同时,还可以通过相频特性发现,在低频段和高频段还会产生超前和滞后的附加相移。基于此图就可以定义几个非常重要的频率参数。首先在中频段放大电路所对应的增益是最大的,将其称为通带增益。实际上,他就是之前一直在利用 h参数等效模型所求取的电压放大倍数。而随着频率的降低和升高,增益都会出现下降。在工程上,规定当增益下降到通带增益的0.707倍时,所对应的两个频率分别称为下限频率和上限频率。0.707是 1 / 2 1/\sqrt{2} 1/2 。那么当放大电路的频率在上下限频率的下一个位置的时候,放大电路的功率将会下降一半,因此这样一条线也称为半功率线。将上下限频率所规定的中间的频率范围称为通频带,也就是带宽。显然,带宽是最重要的一个放大电路的频率参数。因为在这样一个带宽里,可以认为不同频率信号所获得的增益和附加相移是相同的。因此,当他们在输出端叠加的时候,就不会产生幅度和相位失真。

    在这里插入图片描述
    通过这样一个图,可以对一个电路的频率特性一目了然,了解它的上下限,频率和带宽等等重要参数。但是在使用这样一个电路的时候,也会遇到麻烦,因为我们所处理的信号的频率范围非常宽,通常可以从几赫兹到几百兆赫以上。而放大电路的增益,也可能从体内达到百万倍的量级,那如果用线性坐标去描述这样一个幅频特性和相频特性的话显然这个图就非常非常的大了。可以用对数坐标所描述的波特图来在有限的视野之内,全面的了解一个电路的幅频特性和相频特性。所谓的波特图就是在横坐标上改原来的线性增长为指数增长,以对数坐标来表示频率的一个变化,那此时每一个刻度就代表了十倍频;对于幅频特性(纵坐标)来说,以分贝的形式来表示幅度的一个增长。也就是说,以 20log|Au| 的幅值来描述原来的线性增长的幅值,这样就可以极大地来压缩坐标。同时我们可以看到,大部分系统的频率响应,在局部范围之内是比较有规律的,因此我们通常可以将曲线做直线化处理,得到近似的折线化波特图,更加清晰地反映幅频特性和相频特性。

    在这里插入图片描述
    在这里插入图片描述
    这就刚才看到的放大电路的幅频特性和相频特性的波特图,显然此时的横轴仍然是频率,但是此处的频率已经是对数坐标下表示的了,也就是每一个刻度将是十倍频的关系。注意幅频特性的纵坐标已经变成了 20log 的这样一个分贝形式。所以可以看到在这样一个有限的视野之内,就可以对整个放大电路的频率特性一目了然,有效地压缩的坐标。这里需要强调的是,对于一个波特图来说,除了要标识出他的关键频率 fL 和fH 之外,还应该标示出这个折线化之后折线随频率变化的规律,例如每十倍频 -20dB的趋势。另外,还需要注意的是。在 fL 和 fH 处出现了一个拐点,在图中看上去这个拐点所处于的增益,仍然是通带增益 20log|A~usm|,但是实际的波特图中,在此处增益已经出现了下降,下降为原来的 0.707倍。这就是对上下限频率的定义,说明在这样的一个拐点处,增益较通带增益已经下降了3dB。因此通常也可以将上下限频率称为3dB频率。这一点是需要非常关注的。因此通过这样的一个波的图,可以非常全面的了解一个放大电路的频率特性。因此,得到这样的一个波的图,就是对放大电路进行匹配响应的一个主要目标。

    单时间常数RC电路的频率响应

    首先进行定性分析,看看频率对这个电路的影响。当信号频率较低时候,电容C的电抗较大,显然对信号的传输会产生较大的影响,而随着信号频率的逐渐增高,电容C的电抗迅速减小,甚至可以等效为短路,那此时信号就可以畅通无阻了。因此,可以看到,这个电路显然反映出一种阻低频,通高频的相应频率特性,将这样一种频率特性的电路称为高通电路。此外通过定性分析还不难发现,当电容C不在对信号的传输产生影响的时候,反应出输出Uo 应该等于 Ui ,所以电路的通带增益就1,这个电路的最大的增益,也就是通带增益。下面来定量的分析这个电路的频率特性增益的定义仍然是Uo 比上 Ui 。这里只需要将C视为 1/ jwC的电阻利用欧姆定律就可以得到这个电路的一个增益的表达式如下图。此时仍然定义RC为时间常数 τ,从而找到一个关键的频率 fL = 1/2πRC = 1/2πτ。将 fL 代入 Au 表达式,同时用2πf 来取代这里的 w 就可以得到一个关于 f 的增益表达式,此时就可以看到,这个电路增益就是一个频率的函数。取这样一个表达式的模和相角就得到电路的幅频特性和相频特性。

    在这里插入图片描述
    基于相频特性和幅频特性画出波特图

    对数幅频特性

    根据对数要求首先要将幅值做分贝化处理,20log形式,这里fL 和 f 是比值类的形式,那么就可以看看 fL和 f 的几种比较关系。当 f >> fL 时,显然这部分非常小,约等于 0,此时整个对数的幅频特性就等于 0dB,此时对应的就是通带增益幅值为 1 情况;随着频率的减小,当 f << fL 时,显然这一部分就会变得非常大,1 可以忽略不计,表达式就可写成 20lg f f   L   \frac{f}{f~L~} f L f,这反映出当信号小于 fL 时,幅频特性将以每十倍频20dB的速率来衰减;当 f = fL 时,将 fL 带入表达式就可发现,此时对数幅频特性为 -20lg 2 \sqrt{2} 2 ,就是 -3dB,这意味着增益较通带增益下降3dB。就是这个电路的截止频率,下限频率。

    在这里插入图片描述
    根据以上结论就可在对数坐标下画出这个电路折线化的幅频特性——波特图。

    可以看到当大于 fL 时电路的通带增益为 1 ,而随着频率减小将以每十倍频20dB的速率来衰减,频率越低增益的幅值就越小,反应出对低频信号较大的阻碍作用。对于此波特图需要特别强调的是在折线化的波特图中拐点出现在 fL 处,在此处虽然在折线化的波特图中是通带增益 1,但应该知道在此处增益已经下降 3dB。这3dB也是实际的幅频特性和折线化幅频特性的最大误差。

    在这里插入图片描述
    根据相频特性仍然考察 fL 和 f 的关系,当 f >> 10fL 时,显然这部分就约等于 0。那么附加相移就约为 0 °;而当 f << fL 时,此部分就趋于无穷大,此时附加相移就约为 90°;当 f = fL 时,附加相移是 45°。据此就可画出相频特性的波特图。

    在这里插入图片描述
    可以看出在高频段输入和输出信号相位是相同的,而随着信号频率的降低该电路将产生 0 ~ 90°的超前相移。对于这样的相频特性有两点需要注意;首先在相频特性中 fL 这样一个下线频率所对应的的附加相移不是 0°,而是有45°的超前,只有当频率达到了10fL 时候,附加相移才为 0°。其次和幅频特性一样实际的相频特性和折线化的相频特性最大误差也将出现在拐点处在 5.71°左右。

    在这里插入图片描述
    如果将电路中的电容和电阻位置互换,就可以得到他的对偶电路,不妨也来对他进行一个定性的分析。当信号的频率较低的时候,电容C的容抗较大,可以视为开路处理,信号可以畅通无阻地进行传输。随信号频率的增高,电容C的容抗逐渐减小,甚至可以等效为短路。显然,此时 Uo 就无法在响应Ui 的输入。所以可以发现这个电路显然是反映出通低频,阻高频的特性。所以是一个RC低通电路。同时通带增益也是为 1 。跟前面的高通电路一样,也可以首先将C视为 1/ jwC的电阻,求出增益的一个表达式,进而定义时间常数 τ 和关键频率1/2πτ 得到增益和 f 频率的关系。最后就可以得到他的幅频特性和相频特性。

    在这里插入图片描述
    同样也可以得到这个电路的幅频特性和相频特性的波特图。通过波特图,就不难发现,这个电路在频率特性方面的一些特点,首先当信号的频率较低的时候,小于fH 的时候反应出通带增益为 1 的这样的情况,信号的传输能够得以很好的保障。而随着频率的升高,增益的幅值将会以每十倍频 -20dB的速率衰减,表现出对高频信号的一个较强的阻碍作用。因此,这是一个通低频,阻高频的一个低通电路。而通过对 fH 这样一个关键频率的讨论可以发现,在 fH 频率点上电路的增益的幅值下降为通带增益的0.707%也就是衰减了3dB,因此他就是所定义的上限频率。在相频特性上就可以发现,在信号的频率较低的时候,可以保障输出和输入具有相同的相位,随着信号频率的增加,电路将会产生一个0 ~ 90° 的滞后的相移。

    在这里插入图片描述
    通过对一阶RC的高通和低通电路讨论可以得出以下一些结论:

    1、电路的截止频率也就是上限和下限,频率往往取决于电容所在回路的时间常数 τ。2、截止频率的表达式总可以写成 1 2 π τ \frac{1}{2πτ} 2πτ1的形式。这也就说如果能够在电路中找到这样一个电容回路,并且确定他的时间常数,就可以找到截止频率。

    3、对于一阶二阶电路来说,在截止频率处,增益的幅值将会下降3dB,而且会产生正负45°的附加相移。

    4、同时观察实际的波特图的特性,就可以发现。在局部区域内波特图是比较有规律的,因此,在分析中我们可以用折线化的近似波特图来描述电路的频率特性。

    RC低通和高通对比

    负45°的附加相移。

    4、同时观察实际的波特图的特性,就可以发现。在局部区域内波特图是比较有规律的,因此,在分析中我们可以用折线化的近似波特图来描述电路的频率特性。

    RC低通和高通对比

    在这里插入图片描述

    展开全文
  • 光电探测器正常工作所能探测到... 在半导体光电探测器中,影响响应速度的因素主要有[12]:  (1)耗尽区内载流子的渡越时间。当耗尽区内的电场达到饱和时,载流子以最大漂移速率Vs运动,设定耗尽区宽度饿。  
  • 频率响应分析方法

    千次阅读 2012-04-18 09:31:02
    频率响应法的基本思想是把控制系统中的各个变量看成一个信号,而这些信号又是由不同频率的正弦信号合成的;各个变量的运动就是系统对各个不同频率的信号的响应的综合。 这种观察问题和处理问题的方法起源域通信...

    频率响应法的基本思想是把控制系统中的各个变量看成一个信号,而这些信号又是由不同频率的正弦信号合成的;各个变量的运动就是系统对各个不同频率的信号的响应的综合。

    这种观察问题和处理问题的方法起源域通信科学。20世纪30年代,这种观点被引进控制科学,对控制理论的发展起了强大的推动作用。它克服了直接用微分方程研究控制系统的种种困难,解决了许多理论问题和工程问题,迅速形成了分析和综合控制系统的一整套方法,即频域响应法。英国的剑桥学派又将频域响应法推广到多变量系统。

    频率响应法之所以能发挥这样的作用,是因为它具有一系列的优点。首先,这种方法物理意义明显。按照频率响应的的观点,一个控制系统的运动无非是信号在一个一个环节之间依次传递的过程;每个信号又是一些不同频率的正弦信号组成;这些不同频率的正弦信号的振幅和相角在传递过程中,依一定的函数关系变化,就产生形式多样的运动。这种观点比简单的把控制观念看成一个微分方程显然更容易理解,并且更能启发人们区分影响系统的主要因素和次要因素,进而考虑改善系统性能。其次,从信号的传递的角度出发,可以用实验方法求出对象的数学模型,在一点在工程上价值很大,特别是对于机理复杂或机理不明而难以列写微分方程的对象,频域响应观点揭示了重要的处理方法。第三,对于手工计算来说,频域响应法的计算量小。用它分析系统的运动与直接求解系统的微分方程式相比,所需的手工计算量相差非常悬殊。第四,由于频域响应法很大一部分都采用作图,因此这种方法有很强的直观性。

    当然,频率响应法不能用于对非线性系统进行全面分析,尽管它在这方面也获得一定的成绩。因为非线性系统不满足叠加原理,所以从根本上说频率响应法不可能成为研究和设计非线性系统的得力工具。这是它主要的局限性。  

    展开全文
  • 研究结果表明在一年的分析周期内环境温度和结构振动水平是影响桥梁模态频率变化的主要因素,而风速只有达到一定的幅值以后才会对结构的模态参数产生较为显著的影响。研究还表明这三个因素在不同的时间尺度上影响结构...
  • 影响网站打开速度的因素有很多,包括网络带宽、服务器性能、公网传输质量、网页内容设计、DNS 解析时间等。 1 网络宽带 “第一公里”是指万维网流量向用户传送的第一个出口, 是网站...

    finn  岂安科技高级售前顾问  

    多年云安全、大数据、CDN 等领域方案设计和项目管理经验,曾任多个互联网大型项目的售前项目经理。


    1  网站性能现状


    相信都听说过互联网八秒定律:用户访问一个网站时,如果等待网页打开的时间超过8秒,超过30%的用户会放弃等待。根据调查研究,一个网站在10秒内网页打不开,会有40%的用户离开该页面;大部分手机用户愿意等待的加载时间为6-10秒;1秒钟延迟会导致转化率下降7%。



    目前越来越多的互联网网站和应用承载着公司的核心商业价值,每当网站性能出现问题时,直接会影响到公司形象甚至收益,所以如何及时对网站性能进行监测分析,意义重大。

    当前互联网巨头 Google、Facebook 等每年均投入了巨大的人力和物力,来对性能进行监测优化,这印证了高性能网站能够增加流量、提高用户体验,最终增加业务收入、降低运营成本。



    2  影响网站性能的罪魁祸首


    影响网站打开速度的因素有很多,包括网络带宽、服务器性能、公网传输质量、网页内容设计、DNS 解析时间等。


    1 网络宽带


    “第一公里”是指万维网流量向用户传送的第一个出口,是网站服务器接入互联网链路所能提供的带宽。此带宽决定了一个网站能为用户提供的访问速度和并发访问量。一个网站出口带宽越大,能服务的用户就越多;当用户请求数据量超过该网站所能提供的带宽时,就会在出口处形成拥塞,从而导致用户访问受阻。


    2 服务器性能


    衡量服务器性能时,一般会涉及到几个指标。如 CPU、内存、QPS、load、RT,其中 CPU、内存、load 来衡量机器性能,QPS、RT 来衡量应用性能。一般建议 CPU、内存、load、RT 越低越好;QPS 则越大越好。


    3 公网传输影响


    网站服务器到用户之间要经过网站所在的 IDC 或云机房、骨干网、用户所在城域网、用户所在接入网等。如果网站和用户之间距离遥远,比如跨国或者跨多个省份,不可避免的将会带来较长的传输时延,影响用户体验;同时用户接入带宽差、跨越 ISP 也会影响传输效果。这些问题互联网本身未进行解决(CDN、分布式机房等技术除外)。

    如果网站服务器放在海外比如香港、美国、欧洲等地,而用户在国内,此时用户访问该网站的效果也将会打折扣。


    4 网页内容设计


    网页文件的大小是网站能否快速打开的一个重要因素。压缩并减小网页里面的图片、视频文件,可以提升打开速度。

    网站前端很庞大,如果本身资源未做合并和压缩、http请求太多、未设置浏览器缓存、动静态使用不当、代码过于冗余都会造成网页性能瓶颈。


    5 DNS解析时间


    DNS 解析服务是在HTTP连接建立之前的一个过程。从用户主机上调用应用程序的角度看,DNS 是一个提供简单、直接转换服务的黑盒子,实际上 DNS 解析服务相当复杂。

    DNS 解析时间对网站性能打开速度影响非常明显,笔者建议选择稳定可靠的解析服务商,这样在解析速度、处理能力、安全性方面都将有一定保障,另外可通过 DNS 预读取、DNS 缓存、拆分域名来减少 DNS 域名解析时间。


    影响网站性能的几大因素



    3  网站性能监测手段


    市面上常见的能对网站性能监测专业厂商很多,笔者在 CDN厂商呆过几年,对这行业有一些了解。比较知名的有听云、监控宝、博瑞、Gomez、OneAPM 等,这些都属于专业权威的性能监控平台,可以对浏览器、手机应用、服务器性能、网络、API 等多维度监测;其次腾讯云、阿里云、网宿及相关云厂商也有针对网站、服务器、劫持等维度的监控,除了自用以外,也可为接入的客户提供全方位的监测服务;市面上还有些免费即时监测平台如 17ce,由于免费所以采用的监测机的性能上可能会略差一些。当然市场上远不止以上这些性能监测产品,此处略过一百字……


    网站新性能监测厂商


    以某厂商的网站性能监测为例,来具体描述下监测手段:


    某厂商监测原理图


    > > > >

    监测节点


    监测节点分为多种,分别为 lastmile(最后一公里,即用户)、IDC 监测、移动节点监测。Lastmile 即模拟真实用户来向网站发起请求,IDC 监测即从 IDC 机房向网站发起请求,移动节点即从手机端向网站发起请求。此处建议以 lastmile 为主,IDC 监测由于自身网络质量好,监测的效果并不能反应真实的网站性能。


    采用lastmile的网络节点对各大运营商 lastmile 节点的网络状况进行监测,通过分散于全国或全球不同地理位置分布的监测机来模拟真实的用户访问。由于监测节点为私募机器,机器可能会因网络出口或带宽等问题影响监测性能。


    监测节点数量和地理分布均为越多越好。考虑到成本,一般根据网站实际用户的访问情况来定。常见的比如大型电商和视频网站的监测,节点至少要在一二线城市有20-30个,除了电信、联通、移动三大 ISP 外,长宽、教育网、铁通等小 ISP 也需要合理布置。采集频率一般半小时或一小时一次即可。


    > > > >

    监测对象


    通常能监测的对象有图片、页面、视频文件、直播、动态行为、上传过程等,每种对象使用的场景不同。图片、页面、视频文件、直播一般适用于电商、门户网站、视频网站等静态资源较多的行业,用户比较关注资源的加载和播放速度,此类监测最多。一般由于静态资源都会做 CDN 边缘缓存,所以监测的效果都不错;动态行为、上传过程一般适用于登录等交互类的场景,比如企业内部的应用系统,由于动态交互类行为需要实时走公网传输回源,所以监测的效果受制于公网的波动影响,效果一般比较差。


    > > > >

    监测指标


    指标一般包括这几个方面,平均响应时间、可用性、首包时间、DNS 时间、建连时间、内容下载时间、SSL 握手时间(对 HTTPS 协议监测)、重定向时间。

    其中可靠性指访问成功率,该值越高越好;建连时间指用户和 WEB 服务器建立 TCP/IP 连接消耗的时间;首包时间指用户浏览器发起 HTTP 请求结束开始,到收到 WEB 服务器返回的第一个数据包的消耗时间。SSL 握手时间是针对 HTTPS 网站特有,重定向时间是配置了301或302跳转所对应的时间。

    某网站监测效果如下:




    通过针对网站甚至全平台的性能监测,可以发现存在的性能问题并根据性能测试结果进行对应优化以提升系统整体性能。并有效帮助企业改善网站应用的用户体验,提升业务转化,减少用户流失。


    反爬虫


    展开全文
  • 影响MySQL Server性能的相关因素

    千次阅读 2010-07-30 21:29:00
    影响MySQL Server性能的相关因素

    影响MySQL Server性能的相关因素

           推荐大家一本书《MySQL性能调优与架构设计》,写的真是不错,第6章节的内容同样比较精彩,虽然语言很直白话,但是写的很在理,摘取精华部分,整理下来分享给大家。

     

    前言

    大部分的人都一致地认为一个数据库应用系统(这里的数据库应用系统指所有的使用数据库的系统)的性能瓶颈最容易出现于数据的操作方面,而数据库应用系统的大部分数据操作都是通过数据库管理软件所提供的相关接口完成的。所以数据库管理软件也就很自然的成为了数据库应用系统的性能瓶颈所在,这是当前业务比较普遍的一个看法。但我们的应用系统的性能瓶颈真的就是完全是因为数据库管理软件和数据库主机自身的原因吗?我们将通过本章的内容来进行一个较为深入地分析,让大家了解到一个数据库应用系统的性能到底与哪些地方相关,让大家寻找各自应用系统中出现性能的问题的根本原因,而尽可能清楚地知道该如何去优化自己的应用系统。

     

    1.商业需求对性能的影响

    应用系统中的每一个功能在设计初衷肯定都是出于为用户提供某种服务,或者满足用户的某种需求的,但是,并不是每一个功能在最后都能够很成功,甚至有些功能的推出可能在整个系统中是属于画蛇添足的。不仅没有为用户提高任何体验度,也没有为用户改进多少功能易用性,反而在整个系统中成为一个累赘,带来资源的浪费。

     

    一、不合理需求造成资源投入产出比过低

    需求是否合理很多时候可能并不是很容易界定的,尤其是作为技术人员而言,可能更难以确定一个需求的合理性。即使指出,也不一定会被产品经理们认可。那作为技术人员的我们怎么来证明一个需求是否合理呢?

    1)每次产品经理们提出新的项目(或功能需求)的时候,应该要求他们同时给出该项目的预期收益的量化指标,以备项目上先后统计评估投入产出比率。

    2)在每次项目进行过程中,应该详细记录所有的资源投入,包括人力投入,硬件设施的投入以及其他任何项目相关的资源投入。

    3)项目(或功能需求)上线之后,应该及时通过收集相关数据统计出项目的实际收益值,以便计算投入产出比率的时候使用。

    4)技术部门应该尽可能推动设计出一个项目(或功能需求)的投入产出比率的计算规则。在项目上线一段时间之后,通过项目实际收益的统计数据和项目的投入资源量,计算出整个项目的实际投入产出值,并公布给所有参与项目的部门,同时存放以备后查。

    有了实际的投入产出比率,我们就可以和项目立项之初产品经理们的预期投入产出比率做出比较,判定出这个项目做的是否值得。而且当积累了较多的项目投入产出比率之后,我们可以根据历史数据分析出一个项目合理的投入产出比率应该是多少。这样,在项目立项之初,我们就可以判定出产品经理们的预期投入产出比率是否合理,项目是否真的有进行的必要。

    有了实际的投入产出比率之后,我们还可以拿出数据给老板们看,让他们知道功能并非是越多越好,让他知道有些功能是应该撤下来的,即使撤下该功能可能需要投入不少资源。

    实际上,一般而言,在产品开发及运营部门内部都会做上面所说的这些事情。但很多时候可能更多只是一种形式化的过程。在有些比较规范的公司可能也完成了上面的大部分流程,但是要么数据不公开,要么公开给其他部门的数据存在一定的偏差,不具备真实性。

    为什么会这样呢?其实就是一个原因,就是部门之间的利益冲突及业绩冲突问题。产品经理们总是希望尽可能的让用户觉得自己设计的产品功能齐全,让老板觉得自己做了很多事情。但是从来都不会去关心因为做一个功能所带来的成本投入,或者说是不会特别的关心这一点。而且很多时候是因为他们根本就不了解技术,他们只是一群外行却来领导内行,这不得不说是企业管理过程中出现的一个巨大的漏洞,这样由于他们对于技术理解的空白所带来的复杂度给产品本身带来了很多的负面影响。

    这里我们就拿一个看上去非常简单的功能来分析一下。

    需求:一个论坛贴子问题的统计

    附加要求:实时更新

    在很多人看来,这个功能是非常容易实现的,不就是执行一条SELECT COUNT(*)Query就可以得到结果了吗?是的,确实是只需要如此简单的一条Query语句就可以实现了。但是,如果我们采用的不是MyISAM存储引擎,而是使用Innodb的存储引擎,那么大家可以想像一下,如果存放贴子的表已经有上千万贴子的时候,执行这样一条Query语句需要多少成本?恐怕再好的硬件设备,都不可能在10s之内完成一次查询吧。如果我们的访问量再大一些,还有人觉得这是一件简单的事情吗?

    既然这样查询是不行的,那我们是不是该专门为这个功能建立一个表,就只有一个字段,一条记录,就存放这个统计量,每次有新的贴子产生时候,都将这个值增加1,这样我们每次都只需要查询这个表就可以得到结果了,这个效率肯定能够满足要求了。确实,查询效率肯定能够满足需求,可是如果我们的系统贴子产生的很快,在高峰期时候可能每秒就有几十甚至上百个贴子新增操作的时候,恐怕这个统计表又要成为大家的噩梦了。要么因为并发的问题造成统计结果不准确,要么因为锁资源争用严重造成了整体性能的大幅度下降。

    其实这里问题的焦点不应该是实现这个功能的技术细节,而是在于这个功能的附加要求“实时更新”上面。当一个论坛的贴子数量很大之后,到底有多少人会关注这个统计数据是否是实时变化的呢?有多少人在乎这个数据在短时间内是不精确的?我想恐怕不会有人会傻里巴叽地盯着这个统计数据并追究自己发了一个贴子然后回头刷新时候,新页面发现这个统计数字并没有加1.即使明明白白的告诉用户这个统计数据每过多长时间更新一次,那有怎样?难道会有很多用户会因此很不爽吗?

    只要去掉了这个“实时更新”附加条件,我们就可以非常容易地实现这个功能了。就像之前所提到的那样,通过创建一个统计表,然后通过一个定时任务每隔一定时间段去更新一次这里面的统计值,这样即可以解决统计值查询效率问题,又可以保证不影响新发贴的效率,一举两得。

    实际上,在我们应用的系统中还有很多很多类似的功能点可以优化。如果某些场合的列表页面参与列表的数据量达到一个数量级之后,完全可以不用准确的显示这个列表总共有多少条信息,总共分了多少页,而只需要一个大概估计值或者一个时间段之前的统计值。这样就省略了我们的分页程序需要在分以前实时COUNT出满足条件的记录数。

    其实,在很多应用系统中,实时和准实时,精确与基本准确,在很多地方所带来的性能消耗可能是几个性能的差别。在系统性能优化中,应该尽量分析出那些可以不实时和不完全精确的地方,作出一些相应的调整,可能会给大家带来意想不到的巨大性能提升。

     

    二、无用功能堆积使系统过度复杂影响整体性能

    很多时候,为系统增加某个功能可能并不需要花费太多成本,而要想将一个运行了一段时间的功能从原有系统撤下来却是非常困难的。

    首先,对于开发部门,可能要重新整理很多的代码,找出可能存在与增加该功能所编写的代码有交集的其他功能点,删除没有关联的代码,修改有关联的代码;其次,对于测试部门,由于功能的变动,必须要回归测试所有相关的功能点是否正常。可能由于界定困难,不得不将回归范围扩展到很大,测试工作量也很大。最后,所有与撤除下线某个功能相关的工作参与者来说,又无法带来任何实质性的收益,而恰恰相反是,带来的只可能是风险。

    由于上面的这几个因素,可能很少有公司能够有很完善的项目(或者功能)下线机制,也很少有公司能做到及时将系统中某些不合适的功能下线。所以,我们所面对的应用系统可能总是越来越复杂,越来越庞大,短期内的复杂可能并无太大问题,但是随着时间的积累,我们所面对的系统就会变得极其臃肿。不仅维护困难,性能也会越来越差。尤其是有些并不合理的功能,在设计之初或者是刚上线的时候由于数据量较小,带来不了多少性能损耗。可随着时间的推移,数据库中的数据量越来越大,数据检索越来越困难,对整个系统带来的资源消耗也就越来越大。

    而且,由于系统复杂度的不断增加,给后续其他功能的开发带来实现的复杂度,可能很多本来很简单的功能,因为系统的复杂而不得不增加很多的逻辑判断,造成系统应用程序的计算量不断增加,本身性能就会受到影响。而如果这些逻辑判断还需要与数据库交互通过持久化的数据来完成的话,所带来的性能损失就更大,对整个系统的性能影响也就更大了。

    2.系统架构及实现对性能的影响

    一个WEB应用系统,自然离不开WEB应用程序(WEB App)和应用服务器(App Server)。。App Server 我们能控制的内容不多,大多都是使用已经久经考验的成熟产品,大家能做的也就只是通过一些简单的参数设置调整来进行调优,不做细究。而Web App 大部分都是各自公司根据业务需求自行开发,可控性要好很多。所以我们从Web 应用程序着手分析一个应用程序架构的不同设计对整个系统性能的影响将会更合适。

    上一节中商业需求告诉了我们一个系统应该有什么不应该有什么,系统架构则则决定了我们系统的构建环境。就像修建一栋房子一样,在清楚了这栋房子的用途之后,会先有建筑设计师来画出一章基本的造型图,然后还需要结构设计师为我们设计出结构图。系统架构设计的过程就和结构工程好似设计结构图一样,需要为整个系统搭建出一个尽可能最优的框架,让整个系统能够有一个稳定高效的结构体系让我们实现各种商业需求。

     

    一、数据库中存放的数据都是适合在些存放吗?

    对于有些开发人员来说,数据库就是一个操作最方便的万能存储中心,希望什么数据都存放在数据库中,不论是需要持久化的数据,还是临时存放的过程数据,不论是普通的纯文本格式的字符数据,还是多媒体的二进制数据,都喜欢全部塞如数据库中。因为对于应用服务器来说,数据库很多时候都是一个集中式的存储环境,不像应用服务器那样可能有很多台;而且数据库有专门的DBA 去帮忙维护,而不像应用服务器很多时候还需要开发人员去做一些维护;还有一点很关键的就是数据库的操作非常简单统一,不像文件操作或者其他类型的存储方式那么复杂。

    其实我个人认为,现在的很多数据库为我们提供了太多的功能,反而让很多并不是太了解数据库的人错误的使用了数据库的很多并不是太擅长或者对性能影响很大的功能,最后却全部怪罪到数据库身上。

     

    实际上,以下几类数据都是不适合在数据库中存放的:

    1.二进制多媒体数据

    将二进制多媒体数据存放在数据库中,一个问题是数据库空间资源耗用非常严重,另一个问题是这些数据的存储很消耗数据库主机的CPU 资源。这种数据主要包括图片,音频、视频和其他一些相关的二进制文件。这些数据的处理本不是数据库的优势,如果我们硬要将他们塞入数据库,肯定会造成数据库的处理资源消耗严重。

    2.流水队列数据

    我们都知道,数据库为了保证事务的安全性(支持事务的存储引擎)以及可恢复性,都是需要记录所有变更的日志信息的。而流水队列数据的用途就决定了存放这种数据的表中的数据会不断的被INSERTUPDATE DELETE,而每一个操作都会生成与之对应的日志信息。在MySQL 中,如果是支持事务的存储引擎,这个日志的产生量更是要翻倍。而如果我们通过一些成熟的第三方队列软件来实现这个Queue 数据的处理功能,性能将会成倍的提升。

    3.超大文本数据

    对于5.0.3 之前的MySQL 版本,VARCHAR 类型的数据最长只能存放255个字节,如果需要存储更长的文本数据到一个字段,我们就必须使用TEXT 类型(最大可存放64KB)的字段,甚至是更大的LONGTEXT 类型(最大4GB)。而TEXT 类型数据的处理性能要远比VARCHAR 类型数据的处理性能低下很多。从5.0.3 版本开始,VARCHAR 类型的最大长度被调整到64KB 了,但是当实际数据小于255Bytes 的时候,实际存储空间和实际的数据长度一样,可一旦长度超过255 Bytes 之后,所占用的存储空间就是实际数据长度的两倍。

    所以,超大文本数据存放在数据库中不仅会带来性能低下的问题,还会带来空间占用的浪费问题。

     

    二、是否合理的利用了应用层Cache机制?

    对于Web 应用,活跃数据的数据量总是不会特别的大,有些活跃数据更是很少变化。对于这类数据,我们是否有必要每次需要的时候都到数据库中去查询呢?如果我们能够将变化相对较少的部分活跃数据通过应用层的Cache 机制Cache 到内存中,对性能的提升肯定是成数量级的,而且由于是活跃数据,对系统整体的性能影响也会很大。

    当然,通过Cache 机制成功的案例数不胜数,但是失败的案例也同样并不少见。如何合理的通过Cache 技术让系统性能得到较大的提升也不是通过寥寥几笔就能说明的清楚,这里我仅根据以往的经验列举一下什么样的数据适合通过Cache 技术来提高系统性能:

    1.系统各种配置及规则数据

    由于这些配置信息变动的频率非常低,访问概率又很高,所以非常适合存使用Cache

    2.活跃用户的基本信息数据

    虽然我们经常会听到某某网站的用户量达到成百上千万,但是很少有系统的活跃用户量能够都达到这个数量级。也很少有用户每天没事干去将自己的基本信息改来改去。更为重要的一点是用户的基本信息在应用系统中的访问频率极其频繁。所以用户基本信息的Cache,很容易让整个应用系统的性能出现一个质的提升。

    3.活跃用户的个性化定制信息数据

    虽然用户个性化定制的数据从访问频率来看,可能并没有用户的基本信息那么的频繁,但相对于系统整体来说,也占了很大的比例,而且变更频率一样不会太多。从Ebay PayPal 通过MySQL Memory 存储引擎实现用户个性化定制数据的成功案例我们就能看出对这部分信息进行Cache 的价值了。虽然通过MySQL Memory 存储引擎并不像我们传统意义层面的Cache 机制,但正是对Cache 技术的合理利用和扩充造就了项目整体的成功。

    4.准实时的统计信息数据

    所谓准实时的统计数据,实际上就是基于时间段的统计数据。这种数据不会实时更新,也很少需要增量更新,只有当达到重新Build 该统计数据的时候需要做一次全量更新操作。虽然这种数据即使通过数据库来读取效率可能也会比较高,但是执行频率很高之后,同样会消耗不少资源。既然数据库服务器的资源非常珍贵,我们为什么不能放在应用相关的内存Cache 中呢?

    5.其他一些访问频繁但变更较少的数据

    出了上面这四种数据之外,在我们面对的各种系统环境中肯定还会有各种各样的变更较少但是访问很频繁的数据。只要合适,我们都可以将对他们的访问从数据库移到Cache 中。

     

    三、数据库实现都是最精简的吗?

    从以往的经验来看,一个合理的数据存取实现和一个拙劣的实现相比,在性能方面的差异经常会超出一个甚至几个数量级。我们先来分析一个非常简单且经常会遇到类似情况的示例:

    在我们的示例网站系统中,现在要实现每个用户查看各自相册列表(假设每个列表显示10 张相片)的时候,能够在相片名称后面显示该相片的留言数量。这个需求大家认为应该如何实现呢?我想90%的开发开发工程师会通过如下两步来实现该需求:

    1、通过“SELECT id,subject,url FROM photo WHERE user_id = ? limit 10 得到第一页的相片相关信息。

    2、通过第1 步结果集中的10 个相片id 循环运行十次“SELECT COUNT(*) FROM photo_comment WHERE photh_id = ? 来得到每张相册的回复数量然后再封装展现对象。

     

    此外可能还有部分人想到了如下的方案:

    1、和上面完全一样的操作步骤;

    2、通过程序拼装上面得到的10 photo id,再通过in 查询“SELECT photo_id,count(*) FROM photo_comment WHERE photo_id in (?) GROUP BY photo_id 一次得到10 photo 的所有回复数量,再组装两个结果集得到展现对象。

     

    我们来对以上两个方案做一下简单的比较:

    1.MySQL执行的SQL数量来看,第一种解决方案为111+10)条SQL语句,第二种解决方案为2SQL语句(1+1)。

    2.从应用程序与数据库交互来看,第一种为11次,第二种为2次。

    3.从数据库的IO操作来看,简单假设每次SQL1IO,第一种最少为11IO,第二种小于等于11IO,而且只有当数据非常之离散的情况下,才会需要11次。

    4、从数据库处理的查询复杂度来看,第一种为两类很简单的查询,第二种有一条SQL 语句有GROUP BY 操作,比第一种解决方案增加了了排序分组操作。

    5、从应用程序结果集处理来看,第一种11 次结果集的处理,第二中2 次结果集的处理,但是第二种解决方案中第二词结果处理数量是第一次的10 倍。

    6、从应用程序数据处理来看,第二种比第一种多了一个拼装photo_id 的过程。

     

    我们先从以上6 点来做一个性能消耗的分析:

    1、由于MySQL 对客户端每次提交的SQL 不管是相同还是不同,都需要进行完全解析,这个动作主要消耗的资源是数据库主机的CPU,那么这里第一种方案和第二种方案消耗CPU 的比例是11:2SQL 语句的解析动作在整个SQL 语句执行过程中的整体消耗的CPU 比例是较多的。

    2、应用程序与数据库交互所消耗的资源基本上都在网络方面,同样也是112

    3、数据库IO 操作资源消耗为小于或者等于1:1

    4、第二种解决方案需要比第一种多消耗内存资源进行排序分组操作,由于数据量不大,多出的消耗在语句整体消耗中占用比例会比较小,大概不会超过20%,大家可以针对性测试。

    5、结果集处理次数也为11:2,但是第二中解决方案第二次处理数量较大,整体来说两次的性能消耗区别不大。

    6、应用程序数据处理方面所多出的这个photo_id 的拼装所消耗的资源是非常小的,甚至比应用程序与MySQL 做一次简单的交互所消耗的资源还要少。

    综合上面的这6 点比较,我们可以很容易得出结论,从整体资源消耗来看,第二中方案会远远优于第一种解决方案。而在实际开发过程中,我们的程序员却很少选用。主要原因其实有两个,一个是第二种方案在程序代码实现方面可能会比第一种方案略为复杂,尤其是在当前编程环境中面向对象思想的普及,开发工程师可能会更习惯于以对象为中心的思考方式来解决问题。还有一个原因就是我们的程序员可能对SQL 语句的使用并不是特别的熟悉,并不一定能够想到第二条SQL 语句所实现的功能。对于第一个原因,我们可能只能通过加强开发工程师的性能优化意识来让大家能够自觉纠正,而第二个原因的解决就正是需要我们出马的时候了。SQL 语句正是我们的专长,定期对开发工程师进行一些相应的数据库知识包括SQL 语句方面的优化培训,可能会给大家带来意想不到的收获的。

    这里我们还仅仅只是通过一个很长见的简单示例来说明数据层架构实现的区别对整体性能的影响,实际上可以简单的归结为过渡依赖嵌套循环的使用或者说是过渡弱化SQL 语句的功能造成性能消耗过多的实例。后面我将进一步分析一下更多的因为架构实现差异所带来的性能消耗差异。

     

    四、过度依赖数据库Query语句的功能造成数据库操作效率低下

    前面的案例是开发工程师过渡弱化SQL 语句的功能造成的资源浪费案例,而这里我们再来分析一个完全相反的案例:在群组简介页面需要显示群名称和简介,每个群成员的nick_name,以及群主的个人签名信息。

    需求中所需信息存放在以下四个表中:useruser_profilegroupsuser_group

    我们先看看最简单的实现方法,一条SQL 语句搞定所有事情:

    SELECT name,description,user_type,nick_name,sign

    FROM groups,user_group,user ,user_profile

    WHERE groups.id = ?

    AND groups.id = user_group.group_id

    AND user_group.user_id = user.id

    AND user_profile.user_id = user.id

    当然我们也可以通过如下稍微复杂一点的方法分两步搞定:

    首先取得所有需要展示的group 的相关信息和所有群组员的nick_name 信息和组员类别:

    SELECT name,description,user_type,nick_name

    FROM groups,user_group,user

    WHERE groups.id = ?

    AND groups.id = user_group.group_id

    AND user_group.user_id = user.id

    然后在程序中通过上面结果集中的user_type 找到群主的user_id 再到user_profile 表中取得群主的签名信息:

    SELECT sign FROM user_profile WHERE user_id = ?

    大家应该能够看出两者的区别吧,两种解决方案最大的区别在于交互次数和SQL 复杂度。而带来的实际影响是第一种解决方案对user_profile 表有不必要的访问(非群主的profile 信息),造成IO 访问的直接增加在20%左右。而大家都知道,IO 操作在数据库应用系统中是非常昂贵的资源。尤其是当这个功能的PV 较大的时候,第一种方案造成的IO 损失是相当大的。

     

    五、重复执行相同的SQL 造成资源浪费

    这个问题其实是每个人都非常清楚也完全认同的一个问题,但是在应用系统开发过程中,仍然会常有这样的现象存在。究其原因,主要还是开发工程师思维中面向对象的概念太过深入,以及为了减少自己代码开发的逻辑和对程序接口过度依赖所造成的。

    我曾经在一个性能优化项目中遇到过一个案例,某个功能页面一侧是“分组”列表,是一列“分组”的名字。页面主要内容则是该“分组”的所有“项目”列表。每个“项目”以名称(或者图标)显示,同时还有一个SEO 相关的需求就是每个“项目”名称的链接地址中是需要有“分组”的名称的。所以在“项目”列表的每个“项目”的展示内容中就需要得到该项目所属的组的名称。按照开发工程师开发思路,非常容易产生取得所有“项目”结果集并映射成相应对象之后,再从对象集中获取“项目”所属组的标识字段,然后循环到“分组”表中取得需要的”组名“。然后再将拼装成展示对象。

    看到这里,我想大家应该已经知道这里存在的一个最大的问题就是多次重复执行了完全相同的SQL得到完全相同的内容。同时还犯了前面第一个案例中所犯的错误。或许大家看到之后会不相信有这样的案例存在,我可以非常肯定的告诉大家,事实就是这样。同时也请大家如果有条件的话,好好Review 自己所在的系统的代码,非常有可能同样存在上面类似的情形。

    还有部分解决方案要远优于上面的做法,那就是不循环去取了,而是通过Join 一次完成,也就是解决了第一个案例所描述的性能问题。但是又误入了类似于第二个案例所描述的陷阱中了,因为实际上他只需要一次查询就可以得到所有“项目”所属的“分组”的名称(所有项目都是同一个组的)。

    当然,也有部分解决方案也避免了第二个案例的问题,分为两条SQL,两步完成了这个需求。这样在性能上面基本上也将近是数量级的提升了。

    但是这就是性能最优的解决方案了么?不是的,我们甚至可以连一次都不需要访问就获得所需要的“分组”名称。首先,侧栏中的“分组”列表是需要有名称的,我们为什么不能直接利用到呢?

    当然,可能有些系统的架构决定了侧栏和主要内容显示区来源于不同的模板(或者其他结构),那么我们也完全可以通过在进入这个功能页面的链接请求中通过参数传入我们需要的“分组”名称。这样我们就可以完全不需要根据“项目”相关信息去数据库获取所属“分组”的信息,就可以完成相应需求了。当然,是否需要通过请求参数来节省最后的这一次访问,可能会根据这个功能页面的PV 来决定,如果访问并不是非常频繁,那么这个节省可能并不是很明显,而应用系统的复杂度却有所增加,而且程序看上去可能也会不够优雅,但是如果访问非常频繁的场景中,所节省的资源还是比较可观的。

    上面还仅仅只是列举了我们平时比较常见的一些实现差异对性能所带来的影响,除了这些实现方面所带来的问题之外,应用系统的整体架构实现设计对系统性能的影响可能会更严重。下面大概列举了一些较为常见的架构设计实现不当带来的性能问题和资源浪费情况。

    1Cache 系统的不合理利用导致Cache 命中率低下造成数据库访问量的增加,同时也浪费了Cache系统的硬件资源投入。

    2、过度依赖面向对象思想,对系统架构的要求过于完美,造成实现逻辑复杂化。

    3、对可扩展性的过渡追求,促使系统设计的时候将对象拆得过于离散,造成系统中大量的复杂Join语句,而MySQL Server 在各数据库系统中的主要优势在于处理简单逻辑的查询,这与其锁定的机制也有较大关系。

    4、对数据库的过渡依赖,将大量更适合存放于文件系统中的数据存入了数据库中,造成数据库资源的浪费,影响到系统的整体性能,如各种日志信息。

    5、过度理想化系统的用户体验,使大量非核心业务消耗过多的资源,如大量不需要实时更新的数据做了实时统计计算。

    以上仅仅是一些比较常见的症结,在各种不同的应用环境中肯定还会有很多不同的性能问题,可能需要大家通过仔细的数据分析和对系统的充分了解才能找到,但是一旦找到症结所在,通过相应的优化措施,所带来的收益也是相当可观的。

    3.Query语句对系统性能的影响

    前面一节我们介绍了应用系统的实现差异对数据库应用系统整体性能的影响,这一节我们将分析SQL语句的差异对系统性能的影响。

    我想对于各位读者来说,肯定都清楚SQL 语句的优劣是对性能有影响的,但是到底有多大影响可能每个人都会有不同的体会,每个SQL 语句在优化之前和优化之后的性能差异也是各不相同,所以对于性能差异到底有多大这个问题我们我们这里就不做详细分析了。我们重点分析实现同样功能的不同SQL 语句在性能方面会产生较大的差异的根本原因,并通过一个较为典型的示例来对我们的分析做出相应的验证。

    为什么返回完全相同结果集的不同SQL 语句,在执行性能方面存在差异呢?这里我们先从SQL 语句在数据库中执行并获取所需数据这个过程来做一个大概的分析了。

    MySQL Server 的连接线程接收到Client 端发送过来的SQL 请求之后,会经过一系列的分解Parse,进行相应的分析。然后,MySQL 会通过查询优化器模块(Optimizer)根据该SQL 所设涉及到的数据表的相关统计信息进行计算分析,然后再得出一个MySQL 认为最合理最优化的数据访问方式,也就是我们常说的“执行计划”,然后再根据所得到的执行计划通过调用存储引擎借口来获取相应数据。然后再将存储引擎返回的数据进行相关处理,并以Client 端所要求的格式作为结果集返回给Client 端的应用程序。

    注:这里所说的统计数据,是我们通过ANALYZE TABLE 命令通知MySQL对表的相关数据做分析之后所获得到的一些数据统计量。这些统计数据对MySQL 优化器而言是非常重要的,优化器所生成的执行计划的好坏,主要就是由这些统计数据所决定的。实际上,在其他一些数据库管理软件中也有类似相应的统计数据。

    我们都知道,在数据库管理软件中,最大的性能瓶颈就是在于磁盘IO,也就是数据的存取操作上面。而对于同一份数据,当我们以不同方式去寻找其中的某一点内容的时候,所需要读取的数据量可能会有天壤之别,所消耗的资源也自然是区别甚大。所以,当我们需要从数据库中查询某个数据的时候,所消耗资源的多少主要就取决于数据库以一个什么样的数据读取方式来完成我们的查询请求,也就是取决于SQL 语句的执行计划。

    对于唯一一个SQL 语句来说,经过MySQL Parse 之后分解的结构都是固定的,只要统计信息稳定,其执行计划基本上都是比较固定的。而不同写法的SQL语句,经过MySQL Parse 之后分解的结构结构就可能完全不同,即使优化器使用完全一样的统计信息来进行优化,最后所得出的执行计划也可能完全不一样。而执行计划又是决定一个SQL 语句最终的资源消耗量的主要因素。所以,实现功能完全一样的SQL 语句,在性能上面可能会有差别巨大的性能消耗。当然,如果功能一样,而且经过MySQL 的优化器优化之后的执行计划也完全一致的不同SQL 语句在资源消耗方面可能就相差很小了。当然这里所指的消耗主要是IO资源的消耗,并不包括CPU 的消耗。

    下面我们将通过一两个具体的示例来分析写法不一样而功能完全相同的两条SQL 的在性能方面的差异。

     

    示例一

    需求:取出某个group(假设id 100)下的用户编号(id),用户昵称(nick_name)、用户性别(sexuality)、用户签名(sign)和用户生日(birthday),并按照加入组的时间(user_group.gmt_create)来进行倒序排列,取出前20个。

     

    解决方案一

    SELECT id,nick_name

    FROM user,user_group

    WHERE user_group.group_id = 1

    and user_group.user_id = user.id

    ORDER BY gmt_create desc

    limit 100,20;

     

    解决方案二

    SELECT user.id,user.nick_name

    FROM (

    SELECT user_id

    FROM user_group

    WHERE user_group.group_id = 1

    ORDER BY gmt_create desc

    limit 100,20) t,user

    WHERE t.user_id = user.id;

     

    我们先来看看执行计划:

    sky@localhost : example 10:32:13> explain

    -> SELECT id,nick_name

    -> FROM user,user_group

    -> WHERE user_group.group_id = 1

    -> and user_group.user_id = user.id

    -> ORDER BY user_group.gmt_create desc

    -> limit 100,20/G

    *************************** 1. row ***************************

    id: 1

    select_type: SIMPLE

    table: user_group

    type: ref

    possible_keys: user_group_uid_gid_ind,user_group_gid_ind

    key: user_group_gid_ind

    key_len: 4

    ref: const

    rows: 31156

    Extra: Using where; Using filesort

    *************************** 2. row ***************************

    id: 1

    select_type: SIMPLE

    table: user

    type: eq_ref

    possible_keys: PRIMARY

    key: PRIMARY

    key_len: 4

    ref: example.user_group.user_id

    rows: 1

    Extra:

    sky@localhost : example 10:32:20> explain

    -> SELECT user.id,user.nick_name

    -> FROM (

    -> SELECT user_id

    -> FROM user_group

    -> WHERE user_group.group_id = 1

    -> ORDER BY gmt_create desc

    -> limit 100,20) t,user

    -> WHERE t.user_id = user.id/G

    *************************** 1. row ***************************

    id: 1

    select_type: PRIMARY

    table: <derived2>

    type: ALL

    possible_keys: NULL

    key: NULL

    key_len: NULL

    ref: NULL

    rows: 20

    Extra:

    *************************** 2. row ***************************

    id: 1

    select_type: PRIMARY

    table: user

    type: eq_ref

    possible_keys: PRIMARY

    key: PRIMARY

    key_len: 4

    ref: t.user_id

    rows: 1

    Extra:

    *************************** 3. row ***************************

    id: 2

    select_type: DERIVED

    table: user_group

    type: ref

    possible_keys: user_group_gid_ind

    key: user_group_gid_ind

    key_len: 4

    ref: const

    rows: 31156

    Extra: Using filesort

     

    执行计划对比分析:

    解决方案1中的执行计划显示MySQL 在对两个参与Join 的表都利用到了索引,user_group表利用了user_group_gid_ind索引(key: user_group_gid_ind),user 表利用到了主键索引(key:PRIMARY),在参与Join MySQL 通过Where过滤后的结果集与user 表进行Join,最后通过排序取出Join 后结果的“limit 100,20条结果返回。

    解决方案2SQL 语句利用到了子查询,所以执行计划会稍微复杂一些,首先可以看到两个表都和解决方案1一样都利用到了索引(所使用的索引也完全一样),执行计划显示该子查询以user_group 为驱动,也就是先通过user_group 进行过滤并马上进行这一论的结果集排序,也就取得了SQL 中的“limit 100,20条结果,然后与user 表进行Join,得到相应的数据。这里可能有人会怀疑在自查询中从user_group表所取得与user 表参与Join的记录条数并不是20 条,而是整个group_id=1 的所有结果。那么请大家看看该执行计划中的第一行,该行内容就充分说明了在外层查询中的所有的20 条记录全部被返回。

    通过比较两个解决方案的执行计划,我们可以看到第一中解决方案中需要和user 表参与Join 的记录数MySQL 通过统计数据估算出来是31156,也就是通过user_group 表返回的所有满足group_id=1 的记录数(系统中的实际数据是20000)。而第二种解决方案的执行计划中,user 表参与Join 的数据就只有20条,两者相差很大,通过本节最初的分析,我们认为第二中解决方案应该明显优于第一种解决方案。

    下面我们通过对比两个解决觉方案的SQL 实际执行的profile 详细信息,来验证我们上面的判断。由于SQL 语句执行所消耗的最大两部分资源就是IOCPU,所以这里为了节约篇幅,仅列出BLOCK IO CPU两项profile 信息(Query Profiler 的详细介绍将在后面章节中独立介绍):

     

    先打开profiling 功能,然后分别执行两个解决方案的SQL 语句:

    sky@localhost : example 10:46:43> set profiling = 1;

    Query OK, 0 rows affected (0.00 sec)

    sky@localhost : example 10:46:50> SELECT id,nick_name

    -> FROM user,user_group

    -> WHERE user_group.group_id = 1

    -> and user_group.user_id = user.id

    -> ORDER BY user_group.gmt_create desc

    -> limit 100,20;

    +--------+-----------+

    | id     | nick_name |

    +--------+-----------+

    | 990101 | 990101 |

    | 990102 | 990102 |

    | 990103 | 990103 |

    | 990104 | 990104 |

    | 990105 | 990105 |

    | 990106 | 990106 |

    | 990107 | 990107 |

    | 990108 | 990108 |

    | 990109 | 990109 |

    | 990110 | 990110 |

    | 990111 | 990111 |

    | 990112 | 990112 |

    | 990113 | 990113 |

    | 990114 | 990114 |

    | 990115 | 990115 |

    | 990116 | 990116 |

    | 990117 | 990117 |

    | 990118 | 990118 |

    | 990119 | 990119 |

    | 990120 | 990120 |

    +--------+-----------+

    20 rows in set (1.02 sec)

     

    sky@localhost : example 10:46:58> SELECT user.id,user.nick_name

    -> FROM (

    -> SELECT user_id

    -> FROM user_group

    -> WHERE user_group.group_id = 1

    -> ORDER BY gmt_create desc

    -> limit 100,20) t,user

    -> WHERE t.user_id = user.id;

    +--------+-----------+

    | id     | nick_name |

    +--------+-----------+

    | 990101 | 990101 |

    | 990102 | 990102 |

    | 990103 | 990103 |

    | 990104 | 990104 |

    | 990105 | 990105 |

    | 990106 | 990106 |

    | 990107 | 990107 |

    | 990108 | 990108 |

    | 990109 | 990109 |

    | 990110 | 990110 |

    | 990111 | 990111 |

    | 990112 | 990112 |

    | 990113 | 990113 |

    | 990114 | 990114 |

    | 990115 | 990115 |

    | 990116 | 990116 |

    | 990117 | 990117 |

    | 990118 | 990118 |

    | 990119 | 990119 |

    | 990120 | 990120 |

    +--------+-----------+

    20 rows in set (0.96 sec)

     

    查看系统中的profile 信息,刚刚执行的两个SQL 语句的执行profile 信息已经记录下来了:

     

    sky@localhost : example 10:47:07> show profiles/G

    *************************** 1. row ***************************

    Query_ID: 1

    Duration: 1.02367600

    Query: SELECT id,nick_name

    FROM user,user_group

    WHERE user_group.group_id = 1

    and user_group.user_id = user.id

    ORDER BY user_group.gmt_create desc

    limit 100,20

    *************************** 2. row ***************************

    Query_ID: 2

    Duration: 0.96327800

    Query: SELECT user.id,user.nick_name

    FROM (

    SELECT user_id

    FROM user_group

    WHERE user_group.group_id = 1

    ORDER BY gmt_create desc

    limit 100,20) t,user

    WHERE t.user_id = user.id

    2 rows in set (0.00 sec)

    sky@localhost : example 10:47:34> SHOW profile CPU,BLOCK IO io FOR query 1;

    +--------------------+----------+-----------+------------+--------------+---------------+

    | Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |

    +--------------------+----------+-----------+------------+--------------+---------------+

    | (initialization) | 0.000068 | 0 | 0 | 0 | 0 |

    | Opening tables | 0.000015 | 0 | 0 | 0 | 0 |

    | System lock | 0.000006 | 0 | 0 | 0 | 0 |

    | Table lock | 0.000009 | 0 | 0 | 0 | 0 |

    | init | 0.000026 | 0 | 0 | 0 | 0 |

    | optimizing | 0.000014 | 0 | 0 | 0 | 0 |

    | statistics | 0.000068 | 0 | 0 | 0 | 0 |

    | preparing | 0.000019 | 0 | 0 | 0 | 0 |

    | executing | 0.000004 | 0 | 0 | 0 | 0 |

    | Sorting result | 1.03614 | 0.5600349 | 0.428027 | 0 | 15632 |

    | Sending data | 0.071047 | 0 | 0.004 | 88 | 0 |

    | end | 0.000012 | 0 | 0 | 0 | 0 |

    | query end | 0.000006 | 0 | 0 | 0 | 0 |

    | freeing items | 0.000012 | 0 | 0 | 0 | 0 |

    | closing tables | 0.000007 | 0 | 0 | 0 | 0 |

    | logging slow query | 0.000003 | 0 | 0 | 0 | 0 |

    +--------------------+----------+-----------+------------+--------------+---------------+

    16 rows in set (0.00 sec)

    sky@localhost : example 10:47:40> SHOW profile CPU,BLOCK IO io FOR query 2;

    +--------------------+----------+----------+------------+--------------+---------------+

    | Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |

    +--------------------+----------+----------+------------+--------------+---------------+

    | (initialization) | 0.000087 | 0 | 0 | 0 | 0 |

    | Opening tables | 0.000018 | 0 | 0 | 0 | 0 |

    | System lock | 0.000007 | 0 | 0 | 0 | 0 |

    | Table lock | 0.000059 | 0 | 0 | 0 | 0 |

    | optimizing | 0.00001 | 0 | 0 | 0 | 0 |

    | statistics | 0.000068 | 0 | 0 | 0 | 0 |

    | preparing | 0.000017 | 0 | 0 | 0 | 0 |

    | executing | 0.000004 | 0 | 0 | 0 | 0 |

    | Sorting result | 0.928184 | 0.572035 | 0.352022 | 0 | 32 |

    | Sending data | 0.000112 | 0 | 0 | 0 | 0 |

    | init | 0.000025 | 0 | 0 | 0 | 0 |

    | optimizing | 0.000012 | 0 | 0 | 0 | 0 |

    | statistics | 0.000025 | 0 | 0 | 0 | 0 |

    | preparing | 0.000013 | 0 | 0 | 0 | 0 |

    | executing | 0.000004 | 0 | 0 | 0 | 0 |

    | Sending data | 0.000241 | 0 | 0 | 0 | 0 |

    | end | 0.000005 | 0 | 0 | 0 | 0 |

    | query end | 0.000006 | 0 | 0 | 0 | 0 |

    | freeing items | 0.000015 | 0 | 0 | 0 | 0 |

    | closing tables | 0.000004 | 0 | 0 | 0 | 0 |

    | removing tmp table | 0.000019 | 0 | 0 | 0 | 0 |

    | closing tables | 0.000005 | 0 | 0 | 0 | 0 |

    | logging slow query | 0.000004 | 0 | 0 | 0 | 0 |

    +--------------------+----------+----------+------------+--------------+---------------+

     

    我们先看看两条SQL执行中的IO消耗,两者区别就在于“Sorting result”,我们回顾一下前面执行计划的对比,两个解决方案的排序过滤数据的时机不一样,排序后需要取得的数据量一个是20000,一个是20,正好和这里的profile 信息吻合,第一种解决方案的“Sorting result”的IO 值是第二种解决方案的将近500 倍。然后再来看看CPU 消耗,所有消耗中,消耗最大的也是“Sorting result”这一项,第一个消耗多出的缘由和上面IO 消耗差异是一样的。

    结论:通过上面两条功能完全相同的SQL 语句的执行计划分析,以及通过实际执行后profile 数据的验证,都证明了第二种解决方案优于第一种解决方案。同时通过后者的实际验证,也再次证明了我们前面所做的执行计划基本决定了SQL 语句性能。

    4.Schema设计对系统的性能影响

    前面两节中,我们已经分析了在一个数据库应用系统的软环境中应用系统的架构实现和系统中与数据库交互的SQL 语句对系统性能的影响。在这一节我们再分析一下系统的数据模型设计实现对系统的性能影响,更通俗一点就是数据库的Schema 设计对系统性能的影响。

    在很多人看来,数据库Schema 设计是一件非常简单的事情,就大体按照系统设计时候的相关实体对象对应成一个一个的表格基本上就可以了。然后为了在功能上做到尽可能容易扩展,再根据数据库范式规则进行调整,做到第三范式或者第四范式,基本就算完事了。

    数据库Schema 设计真的有如上面所说的这么简单么?可以非常肯定的告诉大家,数据库Schema 设计所需要做的事情远远不止如此。如果您之前的数据库Schema 设计一直都是这么做的,那么在该设计应用于正式环境之后,很可能带来非常大的性能代价。

    由于在后面的“MySQL 数据库应用系统设计”中的“系统架构最优化“这一节中会介较为详细的从性能优化的角度来分析如何如何设计数据库Schema,所以这里暂时先不介绍如何来设计性能优异的数据库Schema 结构,仅仅通过一个实际的示例来展示Schema 结构的不一样在性能方面所带来的差异。

     

    需求概述:一个简单的讨论区系统,需要有用户,用户组,组讨论区这三部分基本功能。

    1、需要存放用户数据的表

    2、需要存放分组信息和存放用户与组关系的表

    3、需要存放讨论信息的表

     

    解决方案:

    原始方案一:分别用用四个表来存放用户,分组,用户与组关系以及各组的讨论帖子的信息如下:

    user 用户表:

    +-------------+---------------+------+-----+---------+-------+

    | Field | Type | Null | Key | Default | Extra |

    +-------------+---------------+------+-----+---------+-------+

    | id | int(11) | NO | | 0 | |

    | nick_name | varchar(32) | NO | | NULL | |

    | password | char(64) | YES | | NULL | |

    | email | varchar(32) | NO | | NULL | |

    | status | varchar(16) | NO | | NULL | |

    | sexuality | char(1) | NO | | NULL | |

    | msn | varchar(32) | YES | | NULL | |

    | sign | varchar(64) | YES | | NULL | |

    | birthday | date | YES | | NULL | |

    | hobby | varchar(64) | YES | | NULL | |

    | location | varchar(64) | YES | | NULL | |

    | description | varchar(1024) | YES | | NULL | |

    +-------------+---------------+------+-----+---------+-------+

    groups 分组表:

    +--------------+---------------+------+-----+---------+-------+

    | Field | Type | Null | Key | Default | Extra |

    +--------------+---------------+------+-----+---------+-------+

    | id | int(11) | NO | | NULL | |

    | gmt_create | datetime | NO | | NULL | |

    | gmt_modified | datetime | NO | | NULL | |

    | name | varchar(32) | NO | | NULL | |

    | status | varchar(16) | NO | | NULL | |

    | description | varchar(1024) | YES | | NULL | |

    +--------------+---------------+------+-----+---------+-------+

    user_group 关系表:

    +--------------+-------------+------+-----+---------+-------+

    | Field | Type | Null | Key | Default | Extra |

    +--------------+-------------+------+-----+---------+-------+

    | user_id | int(11) | NO | MUL | NULL | |

    | group_id | int(11) | NO | MUL | NULL | |

    | user_type | int(11) | NO | | NULL | |

    | gmt_create | datetime | NO | | NULL | |

    | gmt_modified | datetime | NO | | NULL | |

    | status | varchar(16) | NO | | NULL | |

    +--------------+-------------+------+-----+---------+-------+

    group_message 讨论组帖子表:

    +--------------+--------------+------+-----+---------+-------+

    | Field | Type | Null | Key | Default | Extra |

    +--------------+--------------+------+-----+---------+-------+

    | id | int(11) | NO | | NULL | |

    | gmt_create | datetime | NO | | NULL | |

    | gmt_modified | datetime | NO | | NULL | |

    | group_id | int(11) | NO | | NULL | |

    | user_id | int(11) | NO | | NULL | |

    | subject | varchar(128) | NO | | NULL | |

    | content | text | YES | | NULL | |

    +--------------+--------------+------+-----+---------+-------+

     

    优化后方案二:

    user 用户表:

    +-------------+---------------+------+-----+---------+-------+

    | Field | Type | Null | Key | Default | Extra |

    +-------------+---------------+------+-----+---------+-------+

    | id | int(11) | NO | | 0 | |

    | nick_name | varchar(32) | NO | | NULL | |

    | password | char(64) | YES | | NULL | |

    | email | varchar(32) | NO | | NULL | |

    | status | varchar(16) | NO | | NULL | |

    +-------------+---------------+------+-----+---------+-------+

    user_profile 用户属性表(记录与user 一一对应):

    +-------------+---------------+------+-----+---------+-------+

    | Field | Type | Null | Key | Default | Extra |

    +-------------+---------------+------+-----+---------+-------+

    | sexuality | char(1) | NO | | NULL | |

    | msn | varchar(32) | YES | | NULL | |

    | sign | varchar(64) | YES | | NULL | |

    | birthday | date | YES | | NULL | |

    | hobby | varchar(64) | YES | | NULL | |

    | location | varchar(64) | YES | | NULL | |

    | description | varchar(1024) | YES | | NULL | |

    +-------------+---------------+------+-----+---------+-------+

    groups user_group 这两个表和方案一完全一样

    group_message 讨论组帖子表:

    +--------------+--------------+------+-----+---------+-------+

    | Field | Type | Null | Key | Default | Extra |

    +--------------+--------------+------+-----+---------+-------+

    | id | int(11) | NO | | NULL | |

    | gmt_create | datetime | NO | | NULL | |

    | gmt_modified | datetime | NO | | NULL | |

    | group_id | int(11) | NO | | NULL | |

    | user_id | int(11) | NO | | NULL | |

    | author | varchar(32) | NO | | NULL | |

    | subject | varchar(128) | NO | | NULL | |

    +--------------+--------------+------+-----+---------+-------+

    group_message_content 帖子内容表(记录与group_message 一一对应):

    +--------------+---------+------+-----+---------+-------+

    | Field | Type | Null | Key | Default | Extra |

    +--------------+---------+------+-----+---------+-------+

    | group_msg_id | int(11) | NO | | NULL | |

    | content | text | NO | | NULL | |

    +--------------+---------+------+-----+---------+-------+

     

    我们先来比较一下两个解决方案所设计的Schema 的区别。区别主要体现在两点,一个区别是在group_message 表中增加了author 字段来存放发帖作者的昵称,与user 表的nick_name 相对应,另外一个就是第二个解决方案将user 表和group_message 表都分拆成了两个表,关系分别都是一一对应。

    方案二看上去比方案一要更复杂一些,首先是表的数量多了2 个,然后是在group_message 中冗余存放了作者昵称。我们试想一下,一个讨论区系统,访问最多的页面会是什么?我想大家都会很清楚是帖子标题列表页面。而帖子标题列表页面最主要的信息就是都是来自group_message 表中,同时帖子标题后面的作者一般都是通过用户名成(昵称)来展示。按照第一种解决方案来设计的Schema,我们就需要执行类似如下这样的SQL 语句来得到数据:

    SELECT t.id, t.subject,user.id, u.nick_name

    FROM (

    SELECT id, user_id, subject

    FROM group_message

    WHERE group_id = ?

    ORDER BY gmt_modified DESC LIMIT 20

    ) t, user u

    WHERE t.user_id = u.id

     

    但是第二中解决方案所需要执行的SQL 就会简单很多,如下:

    SELECT t.id, t.subject, t.user_id, t.author

    FROM group_message

    WHERE group_id = ?

    ORDER BY gmt_modified DESC LIMIT 20

     

    两个SQL 相比较,大家都能很明显的看出谁优谁劣了,第一个是需要读取两个表的数据进行Join,与第二个SQL 相比性能差距很大,尤其是如果第一个再写的差一点,性能更是非常糟糕,两者所带来的资源消耗就更相差悬殊了。

    不仅仅如此,由于第一个方案中的group_message 表中还包含一个大字段“content”,该字段所存放的信息要占整个表的绝大部分存储空间,但在这条系统中执行最频繁的SQL 之一中是完全不需要该字段所存放信息的,但是由于这个SQL 又没办法做到不访问group_message 表的数据,所以第一条SQL 在数据读取过程中会需要读取大量没有任何意义的数据。

    在系统中用户数据的读取也是比较频繁的,但是大多数地方所需要的用户数据都只是用户的几个基本属性,如用户的id,昵称,密码,状态,邮箱等,所以将用户表的这几个属性单独分离出来后,也会让大量的SQL 语句在运行的时候减少数据的检索量,从而提高性能。

    可能有人会觉得,在我们将一个表分成两个表的时候,我们如果要访问被分拆出去的信息的时候,性能不是就会变差了吗?是的,对于那些需要访问如user signmsn 等原来只需要一个表就可以完成的SQL 来说,现在都需要两条SQL 来完成,性能确实会有所降低,但是由于两个表都是一对一的关联关系,关联字段的过滤性也非常高,而且这样的查询需求在整个系统中所占有的比例也并不高,所以这里所带来的性能损失实际上要远远小于在其他SQL 上所节省出来的资源,所以完全不必为此担心。

    5.硬件环境对系统性能的影响

    之前的所有部分都是介绍整个系统中的软件环境对系统性能的影响,这一节我们将从系统环境来分析对数据库系统的影响,并从数据库服务器主机的角度来做一些针对性的优化建议。

    任何一个系统的硬件环境都会对起性能起到非常关键的作用,这一点我想每一位读者朋友都是非常清楚的。而数据库应用系统环境中,由于数据库自身的特点和在系统中的角色决定了他在整个系统中是最难以扩展的部分。所以在大多数环境下,数据库服务器主机(或者主机集群)的性能在很大程度上决定了整个应用系统的性能。

    既然我们的数据库主机资源如此重要,肯定很多读者朋友会希望知道,数据库服务器主机的各部分硬件到底谁最重要,各部分对整体性能的影响各自所占的比例是多少,以便能够根据这些比例选取合适的主机机型作为数据库主机。但是我只能很遗憾的告诉大家,没有任何一个定律或者法则可以很准确的给出这个答案。

    当然,大家也不必太沮丧。虽然没有哪个法则可以准确的知道我们到底该如何选配一个主机的各部分硬件,但是根据应用类型的不同,总体上还是有一个可以大致遵循的原则可以参考的。

    首先,数据库主机是存取数据的地方,那么其IO 操作自然不会少,所以数据库主机的IO 性能肯定是需要最优先考虑的一个因素,这一点不管是什么类型的数据库应用都是适用的。不过,这里的IO 性能并不仅仅只是指物理的磁盘IO,而是主机的整体IO 性能,是主机整个IO 系统的总体IO 性能。而IO 性能本身又可以分为两类,一类是每秒可提供的IO 访问次数,也就是我们常说的IOPS 数量,还有一种就是每秒的IO 总流量,也就是我们常说的IO 吞吐量。在主机中决定IO 性能部件主要由磁盘和内存所决定,当然也包括各种与IO 相关的板卡。

    其次,由于数据库主机和普通的应用程序服务器相比,资源要相对集中很多,单台主机上所需要进行的计算量自然也就比较多,所以数据库主机的CPU 处理能力也不能忽视。

    最后,由于数据库负责数据的存储,与各应用程序的交互中传递的数据量比其他各类服务器都要多,所以数据库主机的网络设备的性能也可能会成为系统的瓶颈。

    由于上面这三类部件是影响数据库主机性能的最主要因素,其他部件成为性能瓶颈的几率要小很多,所以后面我们通过对各种类型的应用做一个简单的分析,再针对性的给出这三类部件的基本选型建议。

     

    一、典型OLTP 应用系统

    对于各种数据库系统环境中大家最常见的OLTP 系统,其特点是并发量大,整体数据量比较多,但每次访问的数据比较少,且访问的数据比较离散,活跃数据占总体数据的比例不是太大。对于这类系统的数据库实际上是最难维护,最难以优化的,对主机整体性能要求也是最高的。因为他不仅访问量很高,数据量也不小。

    针对上面的这些特点和分析,我们可以对OLTP 的得出一个大致的方向。

    虽然系统总体数据量较大,但是系统活跃数据在数据总量中所占的比例不大,那么我们可以通过扩大内存容量来尽可能多的将活跃数据cache 到内存中;

    虽然IO 访问非常频繁,但是每次访问的数据量较少且很离散,那么我们对磁盘存储的要求是IOPS 表现要很好,吞吐量是次要因素;

    并发量很高,CPU 每秒所要处理的请求自然也就很多,所以CPU 处理能力需要比较强劲;

    虽然与客户端的每次交互的数据量并不是特别大,但是网络交互非常频繁,所以主机与客户端交互的网络设备对流量能力也要求不能太弱。

     

    二、典型OLAP 应用系统

    用于数据分析的OLAP 系统的主要特点就是数据量非常大,并发访问不多,但每次访问所需要检索的数据量都比较多,而且数据访问相对较为集中,没有太明显的活跃数据概念。

    基于OLAP 系统的各种特点和相应的分析,针对OLAP 系统硬件优化的大致策略如下:

    数据量非常大,所以磁盘存储系统的单位容量需要尽量大一些;

    单次访问数据量较大,而且访问数据比较集中,那么对IO 系统的性能要求是需要有尽可能大的每秒IO 吞吐量,所以应该选用每秒吞吐量尽可能大的磁盘;

    虽然IO 性能要求也比较高,但是并发请求较少,所以CPU 处理能力较难成为性能瓶颈,所以CPU 处理能力没有太苛刻的要求;

    虽然每次请求的访问量很大,但是执行过程中的数据大都不会返回给客户端,最终返回给客户端的数据量都较小,所以和客户端交互的网络设备要求并不是太高;

    此外,由于OLAP 系统由于其每次运算过程较长,可以很好的并行化,所以一般的OLAP 系统都是由多台主机构成的一个集群,而集群中主机与主机之间的数据交互量一般来说都是非常大的,所以在集群中主机之间的网络设备要求很高。

     

    三、除了以上两个典型应用之外,还有一类比较特殊的应用系统,他们的数据量不是特别大,但是访问请求及其频繁,而且大部分是读请求。可能每秒需要提供上万甚至几万次请求,每次请求都非常简单,可能大部分都只有一条或者几条比较小的记录返回,就比如基于数据库的DNS 服务就是这样类型的服务。

    虽然数据量小,但是访问极其频繁,所以可以通过较大的内存来cache 住大部分的数据,这能够保证非常高的命中率,磁盘IO 量比较小,所以磁盘也不需要特别高性能的;

    并发请求非常频繁,比需要较强的CPU 处理能力才能处理;

    虽然应用与数据库交互量非常大,但是每次交互数据较少,总体流量虽然也会较大,但是一般来说普通的千兆网卡已经足够了。

    在很多人看来,性能的根本决定因素是硬件性能的好坏。但实际上,硬件性能只能在某些阶段对系统性能产生根本性影响。当我们的CPU 处理能力足够的多,IO 系统的处理能力足够强的时候,如果我们的应用架构和业务实现不够优化,一个本来很简单的实现非得绕很多个弯子来回交互多次,那再强的硬件也没有用,因为来回的交互总是需要消耗时间。尤其是有些业务逻辑设计不是特别合理的应用,数据库Schema 设计的不够合理,一个任务在系统中又被分拆成很多个步骤,每个步骤都使用了非常复杂的Query 语句。笔者曾经就遇到过这样一个系统,该系统是购买的某知名厂商的一个项目管理软件。该系统最初运行在一台Dell2950 PC Server 上面,使用者一直抱怨系统响应很慢,但我从服务器上面的状态来看系统并繁忙(系统并发不是太大)。后来使用者强烈要求通过更换硬件设施来提升系统性能,虽然我一直反对,但最后在管理层的要求下,更换成了一台Sun S880 小型机,主机CPU 的处理能力至少是原来机器的3 倍以上,存储系统也从原来使用本地磁盘换成使用EMC 的中断存储CX300。可在试用阶段,发现系统整体性能没有任何的提升,最终还是取消了更换硬件的计划。

    所以,在应用系统的硬件配置方面,我们应该要以一个理性的眼光来看待,只有合适的才是最好的。并不是说硬件资源越好,系统性能就一定会越好。而且,硬件系统本身总是有一个扩展极限的,如果我们一味的希望通过升级硬件性能来解决系统的性能问题,那么总有一天将会遇到无法逾越的瓶颈。到那时候,就算有再多的钱去砸也无济于事了。

     

    6.Schema设计对系统的性能影响

    虽然本章是以影响MySQL Server 性能的相关因素来展开分析,但实际上很多内容都对于大多数数据库应用系统适用。数据库管理软件仅仅是实现了数据库应用系统中的数据存取操作,和数据的持久化。

    数据库应用系统的优化真正能带来最大收益的就是商业需求和系统架构及业务实现的优化,然后是数据库Schema 设计的优化,然后才是Query 语句的优化,最后才是数据库管理软件自身的一些优化。通过笔者的经验,在整个系统的性能优化中,如果按照百分比来划分上面几个层面的优化带来的性能收益,可以得出大概如下的数据:

    需求和架构及业务实现优化:55%

    Query 语句的优化:30%

    数据库自身的优化:15%

    很多时候,大家看到数据库应用系统中性能瓶颈出现在数据库方面,就希望通过数据库的优化来解决问题,但不管DBA 对数据库多们了解,对Query 语句的优化多么精通,最终还是很难解决整个系统的性能问题。原因就在于并没有真正找到根本的症结所在。

    所以,数据库应用系统的优化,实际上是一个需要多方面配合,多方面优化的才能产生根本性改善的事情。简单来说,可以通过下面三句话来简单的概括数据库应用系统的性能优化:商业需求合理化,系统架构最优化,逻辑实现精简化,硬件设施理性化。

    展开全文
  • 关于B2C电子商务顾客忠诚度影响因素的问卷调查各位受访者:您好!我是重庆工商大学融智学院2014级电子商务专业的大四学生,目前正在进行关于B2C电子商务顾客忠诚度影响因素量化分析的研究,目的在于对京东顾客忠诚度...
  • 2. 从用户生命周期分析客户流失的可能影响因素 5 3. 确定初选变量 6 (二) 预测变量与目标变量的相关性 7 1. 分类变量的直方图检验 7 2. 分类变量的卡方检验 11 3. 连续变量与目标变量的相关性...
  • 无杂散动态范围SFDR(Spurious Free Dynamic range),已经成为一个重要的性能指标,直接影响到通信系统的等级水平,尤其是对数字化的VHF/UHF宽频段接收机,SFDR这个指标,越来越受到设计者与质量监督人员的重视。...
  • 第十六讲 1、本讲主题编号 专题序号 专题名称 子专题号 子专题名称 ...子专题主要内容 ...雷达回波强度的影响因素;雷达遥感及雷达图像的特征 RS-10-01-16 16/1
  • 2.固有频率介绍

    千次阅读 2020-05-11 17:14:17
    1.固有频率的定义 ...2.固有频率影响因素 从上面的公式我们可以看出,结构的固有频率只受刚度分布和质量分布的影响,而阻尼对固有频率影响非常有限。而在百度百科中说固有频率受形状、材质的影响,...
  • 分析表明,焊接电流对激光焊接接头的拉伸性能具有主要影响,而脉宽和频率在对接头拉伸性能的影响方面具有明显的交互作用,且任一单因素对接头拉伸性能的影响效果均小于焊接电流。得到适用于1.5 mm厚TC4薄板的最优...
  • 音高和频率(转)

    万次阅读 多人点赞 2017-01-11 21:56:21
    音高和频率
  • 理论结果表明,质量、阻尼与激励频率影响传递率主要因素。与粘滞阻尼相比,迟滞阻尼隔振效果更好,不仅能降低共振区响应,亦能改善高频区隔振性能。对运动方程进行扫频激励下数值仿真,获得力传递特性数值解。结果...
  • 基于MATLAB的频率分析

    千次阅读 2020-10-29 01:22:22
    1 电力系统频率变化的影响及产生原因 ...当系统的频率偏移过大,主要频率较低时(如果系统装机容量不够,不能满足负荷增长的需要,则可能使系统处于低频下运行)。系统的低频运行,对用户的正常工作和电力系
  • 那么影响服务器性能的首要因素应该是: (1)系统的硬件资源,比如说CPU个数,速度,内存大小等 不过由于硬件技术的飞速发展,现代服务器都不缺乏硬件资源。因此,需要考虑的主要问题是如何从“软环境”来提升...
  • 为研究磁浮轨道梁力学性能问题,以高速磁浮较为常见的24 m跨度复合梁和整体梁为研究对象,对2种梁型的自振特性和列车作用下...2种轨道梁动态变形对列车舒适性的贡献度很小,影响磁浮列车舒适性的主要 因素为不平顺激扰。
  • 存储方式与介质对性能的影响

    千次阅读 2011-08-04 21:55:46
    ...数据的存储方式对应用程序的整体性能有着极大的影响。对数据的存取,是顺利读写还是随机读写?将数据放磁盘上还将数据放flash卡上?多线程读写对性能影响?面对着多种数据存储方式,我们如何选
  • 使用 STM32 测量频率和占空比的几种方法

    万次阅读 多人点赞 2017-11-01 15:26:30
    以前在本科时写的教程文章,主要是把自己当时参赛的方法拿出来做了个总结。 想当年天天水论坛好为人师,现在已经全面转向计算机视觉方向了,颇为感慨。不过,自己的理性选择,个中得失早就意料之中。塞翁失马,焉...
  • 建设数据仓库需要考虑的因素

    千次阅读 2016-10-09 17:01:54
    1.系统分析,确定主题 建立数据仓库的第一个步骤就是通过与业务部门的充分交流,了解建立数据仓库所要解决的问题的真正含义,确定各个主题下的查询分析要求...·操作出现的频率,即业务部门每隔多长时间做一次查询
  • 在Android下,不管是GCM,还是微信,都是通过TCP长连接来进行Push消息的,TCP长连接存活,消息Push就及时,所以要对影响TCP连接寿命的因素进行研究。 4.2.1 NAT超时 大部分移动无线网络运营商都在链路一段...
  • DVFS(Dynamic Voltage and Frequency Scaling)动态电压频率调节,是一种实时的电压和频率调节技术。在 CMOS 电路中功率消耗主要可以分为动态功率消耗和静态功率消耗,公式如下: 其中 C 代表负载电容的容值,V ...
  • 结果表明:雷达工作频率、带宽以及路径电子总量(TEC)是影响成像质量的决定因素。 TEC越大,雷达工作频率越低,信号带宽越大,图像恶化越严重。 P波段的星载 SAR图像中,图像偏移和分辨率扩展可达几十米。文中提出利用点...
  • 研究表明, 闭环信号检测系统的前向增益和输出滤波器的阶数是影响谐波电流测量准确度的主要因素; 在闭环稳定的前提下增大前向增益, 同时降低输出滤波器的阶数, 可有效减小谐波电流的测量误差。搭建了DC FOCT谐波电流...
  • pwm对电机的影响

    2021-05-31 23:59:39
    PWM调速主要靠电压的调整,而电压的变化对直流电机的转矩、机械特性也会造成影响。为研究这种影响的变化规律,设计直流电机驱动电路进行实验,通过调节PWM波的占空比和频率来进行对比试验,然后对实验数据分析计算,...
  • 对于数据工作流程,有必要建立一个从数据需求到数据着陆的完整流程,其中需要包括响应需求变化的时间,频率,方法,范围和影响规范,以及批准和授权系统。 (必须得到相应的批准。人员和领导同意),以便可以实施该...
  • 如何建立线上问题快速响应机制

    千次阅读 2019-05-18 11:33:04
      线上问题通常是指大规模影响生产服务的问题或事件,通俗点说就是"踩雷",线上问题处理的流程也可以看成是"踩雷"、“排雷”、“填雷”、“避雷”,优先级从高到底依次排序;   线上问题的处理,不仅是一项技术...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 24,964
精华内容 9,985
关键字:

影响频率响应的主要因素