必备 SQL 查询优化技巧提升网站访问速度

在这篇文章中,我将介绍如何识别导致性能出现问题的查询,如何找出它们的问题所在,以及快速修复这些问题和其他加快查询速度的方法。

你一定知道,一个快速访问的网站能让用户喜欢,可以帮助网站从Google 上提高排名,可以帮助网站增加转化率。如果你看过网站性能优化方面的文章,例如设置服务器的最佳实现、到干掉慢速代码以及 使用CDN 加载图片,就认为你的 WordPress 网站已经足够快了。但是事实果真如此吗?

使用动态数据库驱动的网站,例如WordPress,你的网站可能依然有一个问题亟待解决:数据库查询拖慢了网站访问速度。

在这篇文章中,我将介绍如何识别导致性能出现问题的查询,如何找出它们的问题所在,以及快速修复这些问题和其他加快查询速度的方法。我会把门户网站 deliciousbrains.com 出现的拖慢查询速度的情况作为实际的案例。

定位

处理慢SQL查询的第一步是找到慢查询。Ashley已经在之前的博客里面赞扬了调试插件Query Monitor,而且这个插件的数据库查询特性使其成为定位慢SQL查询的宝贵工具。

该插件会报告所有页面请求过程中的数据库请求,并且可以通过调用这些查询代码或者原件(插件,主题,WordPress核)过滤这些查询,高亮重复查询和慢查询。

要是不愿意在生产安环境装调试插件(性能开销原因),也可以打开MySQL Slow Query Log,这样在特定时间执行的所有查询都会被记录下来。这种方法配置和设置存放查询位置相对简单。

由于这是一个服务级别的调整,性能影响会小于使用调试插件,但当不用的时候也应该关闭。

理解

一旦你找到了一个你要花很大代价找到的查询,那么接下来就是尝试去理解它并找到是什么让查询变慢。最近,在我们开发我们网站的时候,我们找到了一个要执行8秒的查询。

我们使用WooCommerce和定制版的WooCommerce软件插件来运行我们的插件商店。此查询的目的是获取那些我们知道客户号的客户的所有订阅。

WooCommerce是一个稍微复杂的数据模型,即使订单以自定义的类型存储,用户的ID(商店为每一个用户创建的WordPress)也没有存储在post_author,而是作为后期数据的一部分。订阅软件插件给自义定表创建了一对链接。让我们深入了解查询的更多信息。

把 MySQL 当作朋友

MySQL有一个很方便的语句DESCRIBE,它可以输出表结构的信息,比如字段名,数据类型等等。所以,当你执行DESCRIBE wp_postmeta;你将会看到如下的结果:

你可能已经知道了这个语句。但是你知道DESCRIBE语句可以放在SELECT, INSERT, UPDATE, REPLACE 和 DELETE语句前边使用吗?更为人们所熟知的是他的同义词 EXPLAIN ,并将提供有关该语句如何执行的详细信息。

这是我们查询到的结果:

乍一看,这很难解释。幸运的是,人们通过SitePoint总结了一个理解语句的全面指南。

最重要的字段是type,它描述了一张表是怎么构成的。

如果你想看全部的内容,那就意味着MySQL要从内存读取整张表,增加I/O的速度并在CPU上加载。这种被称为“全表浏览”—稍后将对此进行详细介绍。

rows字段也是一个好的标识,标识着MySQL将要不得不做的事情,它显示了结果中查找了多少行。

Explain也给了我们很多可以优化的信息。例如,pm2表((wp_postmeta),告诉我们是Using filesort,因为我们使用了 ORDER BY语句对结果进行了排序。如果我们要对查询结果进行分组,这将会给执行增加开销。

可视化研究

对于这种类型的研究,MySQL Workbench是另外一个方便,免费的工具。将数据库用MySQL5.6及其以上的版本打开,EXPLAIN的结果可以用JSON格式输出,同时MySQL Workbench将JSON转换成可视化执行语句:

它自动将查询的问题用颜色着重表示提醒用户去注意。我们可以马上看到,连接wp_woocommerce_software_licences(别名l)的表有严重的问题。

解决

你应该避免(https://dev.mysql.com/doc/refman/5.7/en/table-scan-avoidance.html)这种全部表浏览的查询,因为他使用非索引字段order_id去连接wp_woocommerce_software_licences表和wp_posts表。这对于查询慢是常见的问题,而且也是比较容易解决的问题。

索引

order_id在表中是一个相当重要的标志性数据,如果想像这种方式查询,我们需要在列上建立一个索引,除此之外,MySQL将逐字扫描表的每一行,直到找到我们想要的行为止。让我们添加一个索引并看看它是怎么样工作的:

哇,干的漂亮!我们成功的添加了索引并将查询的时间缩短了5s.

了解你的查询语句

检查下查询语句——看看每一个join,每一个子查询。它们做了它们不该做的事了吗?这里能做什么优化吗?

这个例子中,我们把licenses 表和posts 表通过order_id 连接起来同时限制post type 为shop_order。这是为了通过保持数据的完整性来保证我们只使用正确的订单记录,但是事实上这在查询中是多余的。

我们知道这是一个关于安全的赌注,在posts 表中software license 行是通过order_id 来跟 WooCommerce order 相关联的,这在PHP 插件代码中是强制的。让我们移除join 来看看有什么提升没有:

提升并不算很大但现在查询时间低于3 秒了。

缓存所有数据

如果你的服务器默认情况下没有使用MySQL查询缓存,那么你应该开启缓存。

开启缓存意味着MySQL 会把所有的语句和语句执行的结果保存下来,如果随后有一条与缓存中完全相同的语句需要执行,那么MySQL 就会返回缓存的结果。缓存不会过时,因为MySQL 会在表数据更新后刷新缓存。

查询监视器发现在加载一个页面时我们的查询语句执行了四次,尽管有MySQL查询缓存很好,但是在一个请求中重复读取数据库的数据是应该完全避免的。

你的PHP 代码中的静态缓存很简单并且可以很高效的解决这个问题。基本上,首次请求时从数据库中获取查询结果,并将其存储在类的静态属性中,然后后续的查询语句调用将从静态属性中返回结果:

缓存有一个生命周期,具体地说是实例化对象有一个生命周期。如果你正在查看跨请求的查询结果,那么你需要实现一个持久对象缓存。然而不管怎样,你的代码应该负责设置缓存,并且当基础数据变更时让缓存失效。

换位思考

不仅仅是调整查询或添加索引,还有其他方法可以加快查询的执行速度。 我们查询的最慢的部分是从客户ID到产品ID再到加入表格所做的工作,我们必须为每个客户做到。

我们是不是可以在需要的时候抓取客户的数据?如果是那样,那我们就只需要加入一次。

您可以通过创建数据表来存储许可数据,以及所有许可用户标识和产品标识符来对数据进行非规范化(反规范化)处理,并针对特定客户进行查询。

您需要使用INSERT / UPDATE / DELETE上的MySQL触发器来重建表格(不过这要取决于数据来更改的表格),这会显着提高查询数据的性能。

类似地,如果一些连接在MySQL中减慢了查询速度,那么将查询分解为两个或更多语句并在PHP中单独执行它们可能会更快,然后可以在代码中收集和过滤结果。 Laravel 通过预加载在 Eloquent 中就做了类似的事情。

如果您有大量数据和许多不同的自定义帖子类型,WordPress可能会在wp_posts表上减慢查询速度。 如果您发现查询的帖子类型较慢,那么可以考虑从自定义帖子类型的存储模型移动到自定义表格中 - 更多内容将在后面的文章中介绍。

结论

通过这些查询优化方法,我们设法将查询从8秒降低到2秒,并且将查询次数从4次减少到1次。需要说明的是,这些查询时间是在我们开发环境运行时记录的 ,生产环境速度会更快。

这对追踪查询缓慢及其修复等问题是一个有用的指南。 优化查询看起来可能像一个可怕的任务,但只要你尝试一下,并取得一些初步的胜利,你就会开始找到错误,并希望做出进一步改善。

(0)

相关推荐

  • MySQL查询优化--调整内部变量的详解

    MySQL是如此的开放,所以可轻松地进一步调整其缺省设置以获得更优的性能及稳定性.需要优化的一些关键变量如下: 改变索引缓冲区长度(key_buffer) 一般,该变量控制缓冲区的长度在处理索引表(读/写操作)时使用.MySQL使用手册指出该变量可以不断增加以确保索引表的最佳性能,并推荐使用与系统内存25%的大小作为该变量的值.这是MySQL十分重要的配置变量之一,如果你对优化和提高系统性能有兴趣,可以从改变 key_buffer_size变量的值开始. 改变表长(read_buffer_siz

  • MySQL查询优化:LIMIT 1避免全表扫描提高查询效率

    在某些情况下,如果明知道查询结果只有一个,SQL语句中使用LIMIT 1会提高查询效率. 例如下面的用户表(主键id,邮箱,密码): 复制代码 代码如下: create table t_user( id int primary key auto_increment, email varchar(255), password varchar(255) ); 每个用户的email是唯一的,如果用户使用email作为用户名登陆的话,就需要查询出email对应的一条记录. SELECT * FROM t

  • MySQL查询优化之explain的深入解析

    在分析查询性能时,考虑EXPLAIN关键字同样很管用.EXPLAIN关键字一般放在SELECT查询语句的前面,用于描述MySQL如何执行查询操作.以及MySQL成功返回结果集需要执行的行数.explain 可以帮助我们分析 select 语句,让我们知道查询效率低下的原因,从而改进我们查询,让查询优化器能够更好的工作. 一.MySQL 查询优化器是如何工作的MySQL 查询优化器有几个目标,但是其中最主要的目标是尽可能地使用索引,并且使用最严格的索引来消除尽可能多的数据行.最终目标是提交 SEL

  • MySQL查询优化:连接查询排序limit(join、order by、limit语句)介绍

    不知道有没有人碰到过这样恶心的问题:两张表连接查询并limit,SQL效率很高,但是加上order by以后,语句的执行时间变的巨长,效率巨低. 情况是这么一个情况:现在有两张表,team表和people表,每个people属于一个team,people中有个字段team_id. 下面给出建表语句: 复制代码 代码如下: create table t_team ( id int primary key, tname varchar(100) ); create table t_people (

  • 浅谈MySQL中的子查询优化技巧

    mysql的子查询的优化一直不是很友好,一直有受业界批评比较多,也是我在sql优化中遇到过最多的问题之一,你可以点击这里 ,这里来获得一些信息,mysql在处理子查询的时候,会将子查询改写,通常情况下,我们希望由内到外,也就是先完成子查询的结果,然后在用子查询来驱动外查询的表,完成查询,但是恰恰相反,子查询不会先被执行:今天希望通过介绍一些实际的案例来加深对mysql子查询的理解: 案例:用户反馈数据库响应较慢,许多业务动更新被卡住:登录到数据库中观察,发现长时间执行的sql: | 10437

  • MySQL查询优化:用子查询代替非主键连接查询实例介绍

    一对多的两张表,一般是一张表的外键关联到另一个表的主键.但也有不一般的情况,也就是两个表并非通过其中一个表的主键关联. 例如: 复制代码 代码如下: create table t_team ( tid int primary key, tname varchar(100) ); create table t_people ( pid int primary key, pname varchar(100), team_name varchar(100) ); team表和people表是一对多的关

  • php+mysql查询优化简单实例

    本文实例分析了php+mysql查询优化的方法.分享给大家供大家参考.具体分析如下: PHP+Mysql是一个最经常使用的黄金搭档,它们俩配合使用,能够发挥出最佳性能,当然,如果配合Apache使用,就更加Perfect了. 因此,需要做好对mysql的查询优化,下面通过一个简单的例子,展现不同的SQL语句对于查询速度的影响. 存在这样的一张表test,它有一个自增的id作为主索引,现在要查询id号处于某一个范围内的记录,可以使用如下SQL语句: 复制代码 代码如下: SELECT * FROM

  • 必备 SQL 查询优化技巧提升网站访问速度

    在这篇文章中,我将介绍如何识别导致性能出现问题的查询,如何找出它们的问题所在,以及快速修复这些问题和其他加快查询速度的方法. 你一定知道,一个快速访问的网站能让用户喜欢,可以帮助网站从Google 上提高排名,可以帮助网站增加转化率.如果你看过网站性能优化方面的文章,例如设置服务器的最佳实现.到干掉慢速代码以及 使用CDN 加载图片,就认为你的 WordPress 网站已经足够快了.但是事实果真如此吗? 使用动态数据库驱动的网站,例如WordPress,你的网站可能依然有一个问题亟待解决:数据库

  • 30个mysql千万级大数据SQL查询优化技巧详解

    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:select id from t where num is null可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:select id from t where num=0 3.应尽量避免在 where 子句中使用!=或<>操作符,否则引擎将放弃使用

  • nginx中gzip压缩提升网站速度的实现方法

    为啥使用gzip压缩 开启nginx的gzip压缩,网页中的js,css等静态资源的大小会大大的减少从而节约大量的带宽,提高传输效率,给用户快的体验. nginx实现gzip nginx实现资源压缩的原理是通过默认集成的ngx_http_gzip_module模块拦截请求,并对需要做gzip的类型做gzip,使用非常简单直接开启,设置选项即可.. gzip生效后的请求头和响应头 Request Headers: Accept-Encoding:gzip,deflate,sdch Response

  • Laravel网站打开速度优化的方法汇总

    前言 Laravel是一个功能强大的框架,组件很多,代码也很庞大,它的易用方便是牺牲了性能的,即便如此它仍然是一个优秀的框架,但在正式环境下要做好优化提升网站的打开速度.下面这篇文章主要给大家介绍了关于Laravel网站打开速度优化的一些方法技巧,下面话不多说,来一起看看详细的介绍: 一.关闭debug 打开.env文件,把debug设置为false. APP_ENV=local APP_DEBUG=false APP_KEY=base64:sT/aTFeaE13eyao1Raee6jC9Ff+

  • HTTP与HTTPS对访问速度、性能等的影响

    1 前言 HTTPS 在保护用户隐私,防止流量劫持方面发挥着非常关键的作用,但与此同时,HTTPS 也会降低用户访问速度,增加网站服务器的计算资源消耗. 本文主要介绍 https 对用户体验的影响. 2 HTTP与HTTPS的概念和区别 (1)HTTPS(全称:Hypertext Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版.即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容

  • WordPress网站访问慢解决方案细图文教程

    前言 之前自己搭建一个WordPress个人网站:https://zhanghan.xin:最近发现访问比较慢,于是乎进行了排查,下面是优化的方案. 优化前: 加载耗时:21秒+ 优化后: 加载耗时:250毫秒 优化后访问速度提升84倍+ 解决方案流程图 流程图 问题&解决方案&验证 定位问题(加载一个CSS超时) 解决步骤 下载访问超时的CSS(Google浏览器中F12中可以找到加载CSS地址)并保存到本地(用可以连上google网络) https://fonts.googleapis

  • js 利用image对象实现图片的预加载提高访问速度

    大量采用高解析度的图像的确可以让一个Web站点容光焕发.但同样也会造成站点访问速度下降--图片是文件,文件就要占用带宽,而带宽直接同访问等待时间相关.现在,让我们来学习一种名为图像预装载(image preloading)的小技巧来提高图像访问速度. 一些浏览器试图通过在本地缓存中保存这些图片来解决此问题.这样一来可以顺序调用这些图片--但对于首次使用这些图片的时候仍然会存在延时.预装载就是一种在需要图片之前就将图片下载到缓存的技术.采用这样的方式可以使当确实需要显示图片时迅速将其从缓存中恢复回

  • .net 应对网站访问压力的方案总结

    开年比较空,抽时间写个博文,总结下自己工作里的一些应对网站访问压力的技术方案. 自己项目现在大概一天50W的pv.已从前端到后端的顺序总结下自己用的一些方案. 一. 前端页面: 1.首先减少资源的大小,能用小图,就用小图.引用第三方js用mini 压缩版的js. 2.用CDN减少服务器访问的压力,将图片,css,js文件放到CDN上.用户从cdn缓存获取资源的速度远快与访问服务器获取的速度.(还有网络关系,cdn网络快) 3.耗时长的js可以异步请求后加载. 二.服务器负载均衡: 负载均衡解决方

  • js实现网页图片延时加载 提升网页打开速度

    提升网页加载速度的方法有很多种,用 jquery.lazyload.js 实现图片异步延迟加载,对于页面包含图片较多的网站来说,会是个不错的提升网页打开速度的方法.代码君网站栏目页列表左侧,在PC端预览时能看到一个文章略缩图展示模块,一定程度上会延长网页加载时间.本文采用图片异步延迟加载的方法,来提升本站页面加载速度. 图片异步加载,就是不必一次性把页面的所有图片都加载显示出来,等用户滑动滚动条到某个位置时才会加载显示相应位置的图片,这样能很好地提升网页加载速度,进一步提升用户体验. 有很多技术

  • 几种延迟加载JS代码的方法加快网页的访问速度

    本文介绍了如何延迟javascript代码的加载,加快网页的访问速度. 当一个网站有很多js代码要加载,js代码放置的位置在一定程度上将会影像网页的加载速度,为了让我们的网页加载速度更快,本文总结了一下几个注意点: 1.延迟加载js代码 复制代码 代码如下: <script type="text/javascript" src="" id="my"></script> <script type="text/

随机推荐