使用 2GB+ 加速单个表上的 SQL 查询

Posted

技术标签:

【中文标题】使用 2GB+ 加速单个表上的 SQL 查询【英文标题】:Speed up SQL queries on a single table with 2GB+ 【发布时间】:2017-04-27 10:22:47 【问题描述】:

我正在 mysql 数据库的一个非常大的表中运行关于广告收入的查询。它包含许多维度,例如设备类别、日期、广告客户、垂直、creative_size、位置等,以及一些指标,如投放的展示次数、点击次数和收入。

表格用于展示广告效果,因此通常按一维或二维分组并按维度过滤。

我已将所有内容放在一张表中以避免连接并使其尽可能快,但由于维度的数量,尤其是。广告客户,表很大,已经超过 2.8Gb 并且还在增长。

我已经尝试过索引和分区,但它仍然很慢,所以我正在考虑通过按一组较小的维度对数据进行分组来创建一个较小的版本,省略广告客户列,即

Select date, creative_size, device_class,ssp,billing_type, location,
       ad_impressions, clicks, revenue
  from ADS
 group by date,creative_size,device_class,ssp,billing_type,location

这将大大减少行数。

我试图将它用作视图,但它不是永久存储的,因此需要更长的时间。如何创建这样的表并根据另一个表使其保持最新状态?我需要编写脚本还是可以使用一些内置的 MySQL 功能?这是一个可行的方法吗?我当然愿意接受其他解决方案:)

【问题讨论】:

如果您阅读本文,尤其是关于查询性能的部分,它将帮助您获得更好的答案。 meta.***.com/a/271056 这个问题对于 Stack Overflow 格式来说太宽泛了。 Ollie's 很好,但如果您需要更多帮助,我们确实需要 SHOW CREATE TABLE 和实际查询。还要检查 innodb_buffer_pool_size 对于这么小的 RAM 大约是 600M。 【参考方案1】:

你说对了,MySQL 的 VIEW 对象对查询性能没有帮助。用行业术语来说,它们不是“物化的观点”。

您尚未向我们披露您使用的实际查询或大表的实际布局。所以具体的建议是不可能的。

您有一些可能的方法来提高查询性能。

    按照您的建议,从您的详细信息表中生成一些聚合表。如果您能够处理稍微陈旧的数据,您可以在一夜之间重新生成它们。

    如果您使用特定查询,请调查创建compound covering indexes to accelerate those queries。

查看您问题中的查询。首先,我想它应该有一些 SUM 项目,就像这样。我还将您提到的date 更改为DATE(date),以便在摘要中仅获取日期,而不是日期和时间。 (也许这已经在你的表中完成了。如果是这样,请不要再这样做了。)

Select DATE(date), creative_size, device_class,ssp,billing_type, location,
       SUM(ad_impressions), SUM(clicks), SUM(revenue)
  from ADS
 group by DATE(date),creative_size,device_class,ssp,billing_type,location

其次,这个没有任何WHERE 子句。如果您确实添加了WHERE 子句,您(几乎可以肯定)需要不同的复合覆盖索引。您可以在别处阅读有关如何使用带有 WHERE 子句的覆盖索引的信息。

第三,这个查询可以通过一个特定的复合索引来加速:在GROUP BYSELECT 子句中提到的所有列上的索引。 GROUP BY 子句中的列应在索引中排在第一位,通常与GROUP BY 中的顺序相同。你会像这样创建这样的索引。

 CREATE INDEX summary_1 ON ADS 
              (date, creative_size, device_class,ssp,billing_type, location,
               ad_impressions, clicks, revenue);

这很有帮助,因为 MySQL 的查询计划器可以按顺序读取索引以满足您的查询,而无需遵循指向您的表的指针。

第四,你可以做到

CREATE TABLE ad_summary AS
Select date, creative_size, device_class,ssp,billing_type, location,
       SUM(ad_impressions), SUM(clicks), SUM(revenue)
  from ADS
 group by date,creative_size,device_class,ssp,billing_type,location;

这是一个穷人的物化视图。 (如果您使用 Oracle,您可以使用他们的物化视图,我们将其 以前称为富人的物化视图。 -- 以前因为 Oracle 太贵了。)

第五,您可以对汇总表进行日期限制(如果这适用于您的应用程序)。通过在查询中添加类似这样的内容来做到这一点。

  WHERE date >= CURDATE() - INTERVAL 7 DAY

这个特定的WHERE 子句可以使用相同的复合覆盖索引,因为它对date 进行范围扫描,并且该列在索引中的第一个。

这里有一些关于磨削超大桌子的一般意见供您考虑。

像您这样的表上的大量单列索引通常对性能有害。 MySQL 不会在单个查询中很好地利用单个表中的多个索引。 SELECT *肯定对性能有害,尤其是当您有很多列时。相反,请枚举您需要的列。 避免在大型查询中使用ORDER BY 子句,除非您知道自己需要它们。 http://use-the-index-luke.com/ 是一个很好的参考,可以让这些东西正常工作。

【讨论】:

More 在汇总表上。

以上是关于使用 2GB+ 加速单个表上的 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

有啥方法可以在同一个大表上使用 3x UNION All 来加速复杂查询?

Access 中 SQL 链接表上的 UPDATE 查询的“操作必须使用可更新查询”

一个表上的简单 SQL 查询

SQL - 连接表上的查询

更新查询在同一张表上的 Sql 查询死锁

小表上的简单 SQL 查询执行时间过长