SQL查询优化技术提高网站访问速度
浏览:73 时间:2023-10-16

您必须知道用户可以喜欢快速访问的网站,可以帮助网站提高Google的排名,并可以帮助网站提高转化率。如果您已经看过有关网站性能优化的文章,例如设置服务器的最佳实现,杀死慢速代码以及使用CDN加载图像,您认为您的WordPress网站足够快。但情况确实如此吗?

使用动态数据库驱动的网站(如WordPress),您的网站可能仍然存在需要解决的问题:数据库查询会降低网站访问速度。

在本文中,我将向您展示如何识别导致性能问题的查询,如何找出它们的位置,以及如何快速修复它们以及其他加速查询的方法。我将使用门户网站deliciousbrains.com上的情况来降低查询速度作为一个实际案例。

 定位

处理慢速SQL查询的第一步是查找慢查询。 Ashley已经赞扬了之前博客中的调试插件Query Monitor,而插件的数据库查询功能使其成为查找慢速SQL查询的有用工具。该插件在所有页面请求期间报告数据库请求,并可以通过调用这些查询代码或原始(插件,主题,WordPress核心)来过滤这些查询,突出显示重复和慢速查询。

如果您不愿意在生产环境中安装插件(出于性能开销的原因),您还可以打开MySQL慢查询日志,以便记录在特定时间执行的所有查询。这种存储查询位置的配置和设置方法相对简单。由于这是服务级别调整,因此性能影响将小于使用调试插件,但应在不使用时关闭。

理解

一旦找到了一个价格合理的查询,下一步就是尝试理解它并找出导致查询速度变慢的原因。最近,当我们开发网站时,我们发现了一个需要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必须执行的操作,并显示在结果中找到了多少行。

解释还为我们提供了许多可以优化的信息。例如,pm2表((wp_postmeta)告诉我们使用filesort,因为我们使用ORDER BY语句对结果进行排序。如果我们想要对查询结果进行分组,这将增加执行的开销。

可视化研究

对于这种类型的研究,MySQL Workbench是另一种方便,免费的工具。使用MySQL 5.6及更高版本打开数据库,EXPLAIN的结果可以以JSON格式输出,MySQL Workbench将JSON转换为可视化执行语句:

它会自动提醒用户注意查询的问题。我们可以立即看到连接wp_woocommerce_software_licences(别名l)的表存在严重问题。

  解决

您应该避免对所有表浏览进行此类查询,因为他使用非索引字段order_id连接到wp_woocommerce_software_licences表和wp_posts表。这是慢查询的常见问题,也是一个相对容易解决的问题。

 索引

Order_id是表中非常重要的标志性数据。如果要以这种方式查询,我们需要在列上创建索引。此外,MySQL将逐字扫描表格的每一行,直到找到我们想要的内容。行为已停止。让我们添加一个索引,看看它是如何工作的:

CREATE INDEX order_id ON wp_woocommerce_software_licences(order_id)

哇,真漂亮!我们成功添加了索引并将查询时间缩短了5秒。

  了解你的查询语句

检查下面的查询——查看每个连接,每个子查询。他们做了他们不该做的事情?你能在这里优化吗?

在此示例中,我们通过order_id连接licenses表和posts表,并将post类型限制为shop_order。这是为了确保我们仅通过维护数据的完整性来使用正确的订单记录,但实际上这在查询中是多余的。我们知道这是一个安全的赌注。 posts表中的软件许可证行通过order_id与WooCommerce订单相关联,这在PHP插件代码中是必需的。让我们删除联接以查看是否有任何改进:

促销不是太大,但现在查询时间不到3秒。

 缓存一切数据

如果您的服务器默认不使用MySQL查询缓存,则应启用缓存。打开缓存意味着MySQL将保存所有语句和语句执行的结果。如果有一个与缓存中的语句完全相同的语句,MySQL将返回缓存的结果。缓存不会过时,因为MySQL会在更新表数据后刷新缓存。

查询监视器发现我们的查询语句在加载页面时执行了四次。虽然MySQL查询缓存很好,但应该完全避免在一个请求中重复读取数据库数据。 PHP代码中的静态缓存很简单,可以非常有效地解决这个问题。基本上,第一次从数据库中检索请求并将其存储在类的静态属性中时,后续的查询语句将返回静态属性的结果:

WC_Software_Subscription {

受保护的静态$ subscriptions=array();

公共静态函数get_user_subscriptions($ user_id){

if(isset(static:: $ subscriptions [$ user_id])){

返回静态:: $ subscriptions [$ user_id];

}

全球$ wpdb;

$ sql='...';

$ results=$ wpdb-> get_results($ sql,ARRAY_A);

静态:: $ subscriptions [$ user_id]=$ results;

返回$ results;

}

}

缓存具有生命周期,特别是实例化对象具有生命周期。如果要查看跨请求的查询结果,则需要实现持久对象缓存。但是,您的代码应负责设置缓存并在基础数据更改时使缓存无效。

 跳出箱子外思考

除了调整查询或添加索引之外,还有其他方法可以加快查询的执行速度。我们查询中最慢的部分是从客户ID到产品ID到连接表单的工作,我们必须为每个客户执行此操作。我们可以在需要时获取客户的数据吗?如果是这样,那么我们只需要加入一次。

您可以创建数据表来存储许可证数据,以及所有许可的用户ID和产品标识符,以对特定客户的数据进行非规范化(非规范化)和查询。您需要在INSERT/UPDATE/DELETE上使用MySQL触发器来重建表(尽管这取决于更改表的数据),这将显着提高查询数据的性能。

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

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