如何在 MySQL 中重用一个巨大的查询
How to reuse a huge query in MySQL
我有一个非常大的查询,它从许多 table 中获取数据并按所有非计算列对它们进行分组。而且我需要多次重用此查询,但要使用其他分组和过滤。在 MSSQL 中,我为此目的使用 CTE 或临时 table,但 MySQL 不支持 CTE,我不能在同一查询中多次引用临时 table(这是MySQL 的可悲和不合逻辑的限制)。
SELECT
t1.VideoId,
t1.RegionId,
t1.CountryId,
t1.PerCountryCount,
t2.PerRegionCount
FROM (
SELECT
VideoId,
RegionId,
CountryId,
SUM(PlayCount) PerCountryCount
FROM TrackedData
GROUP BY VideoId, RegionId, CountryId
) t1
INNER JOIN (
SELECT
VideoId,
RegionId,
SUM(PlayCount) PerRegionCount
FROM TrackedData
GROUP BY VideoId, RegionId
) t2
此示例已简化但显示了问题所在。 t1 查询有更详细的数据,我想在 t2 查询中重用它,因为在实际项目中很难在 t1 查询中获取数据(百万行、许多过滤器和分组等)。我想重用这个查询的第二个原因是查询长度。我不想重复只更改了大约 60 行代码的查询。
MySQL 中的解决方法是创建多个临时 table。您可以使用临时 table 作为来源来填充另一个。这是我们使用的方法。 (是的,使用单个临时 table 会更有效,但是 MySQL 不允许多次引用同一个临时 table。)
另一种方法是创建一个常规 table 而不是临时 table。这有很多缺点。一个大问题是被放弃的 tables 不会自动删除。如果你走这条路,你无疑会想要:
- 为这些 "temporary" 工作使用单独的数据库 tables
- 一个定期安排的定期清理例程,以丢弃旧的和废弃的 tables
- table 的严格命名约定,table名称使用特殊前缀,后跟日期时间字符串和会话 ID,然后是 "name" table.
清理例程可以根据年龄(基于日期时间字符串,但要注意更改时区设置的客户端的含义)和SHOW PROCESSLIST 中不再存在会话。 (我在那里使用了 "and" 这个词……我们想要删除满足其中任何一个条件的 table。)
创建这些工作的代码 tables 应该删除这些 tables,但即使这样,也会有异常终止而留下 tables。
(就个人而言,我会避免使用第二种方法,而只是使用多个临时 tables。)
作为使用多个临时 tables 的演示:
CREATE TEMPORARY TABLE _t1_ AS
SELECT VideoId
, RegionId
, CountryId
, SUM(PlayCount) AS PerCountryCount
FROM TrackedData
GROUP BY VideoId, RegionId, CountryId
;
CREATE INDEX _t1_IX1
ON _t1_ (VideoId, RegionId, PerCountryCount);
CREATE TEMPORARY TABLE _t2_ AS
SELECT VideoId
, RegionId
, SUM(PerCountryCount) AS PerRegionCount
FROM _t1_
GROUP BY VideoId, RegionId
;
CREATE INDEX _t2_IX1
ON _t2_ (VideoId, RegionId, PerRegionCount)
;
请注意,在 t1 上定义 suitable 索引将提高填充 t2.
的性能
您可以使用视图的概念重用查询:
https://dev.mysql.com/doc/refman/8.0/en/view-algorithms.html
简单的例子,实际上big_ass_select_query可能有一堆连接
DROP VIEW IF EXISTS big_ass_select_query;
CREATE VIEW big_ass_select_query AS
SELECT col1 from table1;
将其用作普通查询
SELECT * FROM big_ass_select_query WHERE col1 > 1;
我有一个非常大的查询,它从许多 table 中获取数据并按所有非计算列对它们进行分组。而且我需要多次重用此查询,但要使用其他分组和过滤。在 MSSQL 中,我为此目的使用 CTE 或临时 table,但 MySQL 不支持 CTE,我不能在同一查询中多次引用临时 table(这是MySQL 的可悲和不合逻辑的限制)。
SELECT
t1.VideoId,
t1.RegionId,
t1.CountryId,
t1.PerCountryCount,
t2.PerRegionCount
FROM (
SELECT
VideoId,
RegionId,
CountryId,
SUM(PlayCount) PerCountryCount
FROM TrackedData
GROUP BY VideoId, RegionId, CountryId
) t1
INNER JOIN (
SELECT
VideoId,
RegionId,
SUM(PlayCount) PerRegionCount
FROM TrackedData
GROUP BY VideoId, RegionId
) t2
此示例已简化但显示了问题所在。 t1 查询有更详细的数据,我想在 t2 查询中重用它,因为在实际项目中很难在 t1 查询中获取数据(百万行、许多过滤器和分组等)。我想重用这个查询的第二个原因是查询长度。我不想重复只更改了大约 60 行代码的查询。
MySQL 中的解决方法是创建多个临时 table。您可以使用临时 table 作为来源来填充另一个。这是我们使用的方法。 (是的,使用单个临时 table 会更有效,但是 MySQL 不允许多次引用同一个临时 table。)
另一种方法是创建一个常规 table 而不是临时 table。这有很多缺点。一个大问题是被放弃的 tables 不会自动删除。如果你走这条路,你无疑会想要:
- 为这些 "temporary" 工作使用单独的数据库 tables
- 一个定期安排的定期清理例程,以丢弃旧的和废弃的 tables
- table 的严格命名约定,table名称使用特殊前缀,后跟日期时间字符串和会话 ID,然后是 "name" table.
清理例程可以根据年龄(基于日期时间字符串,但要注意更改时区设置的客户端的含义)和SHOW PROCESSLIST 中不再存在会话。 (我在那里使用了 "and" 这个词……我们想要删除满足其中任何一个条件的 table。)
创建这些工作的代码 tables 应该删除这些 tables,但即使这样,也会有异常终止而留下 tables。
(就个人而言,我会避免使用第二种方法,而只是使用多个临时 tables。)
作为使用多个临时 tables 的演示:
CREATE TEMPORARY TABLE _t1_ AS
SELECT VideoId
, RegionId
, CountryId
, SUM(PlayCount) AS PerCountryCount
FROM TrackedData
GROUP BY VideoId, RegionId, CountryId
;
CREATE INDEX _t1_IX1
ON _t1_ (VideoId, RegionId, PerCountryCount);
CREATE TEMPORARY TABLE _t2_ AS
SELECT VideoId
, RegionId
, SUM(PerCountryCount) AS PerRegionCount
FROM _t1_
GROUP BY VideoId, RegionId
;
CREATE INDEX _t2_IX1
ON _t2_ (VideoId, RegionId, PerRegionCount)
;
请注意,在 t1 上定义 suitable 索引将提高填充 t2.
的性能您可以使用视图的概念重用查询:
https://dev.mysql.com/doc/refman/8.0/en/view-algorithms.html
简单的例子,实际上big_ass_select_query可能有一堆连接
DROP VIEW IF EXISTS big_ass_select_query;
CREATE VIEW big_ass_select_query AS
SELECT col1 from table1;
将其用作普通查询
SELECT * FROM big_ass_select_query WHERE col1 > 1;