我有一个庞大的查询,用于在很多表(每个表都有数千行)上执行 UNION ALL,然后在返回之前输出到一个临时表。
旧形式:
SELECT *
FROM (SELECT `a` AS `Human readable A`,
`b` AS `Human readable B`,
`c` AS `Human readable C`,
FROM `table1`
UNION ALL
SELECT
`a` AS `Human readable A`,
`b` AS `Human readable B`,
`c` AS `Human readable C`,
FROM `table2`
UNION ALL
SELECT
`a` AS `Human readable A`,
`b` AS `Human readable B`,
`c` AS `Human readable C`,
FROM `table3`
) AS temp_table
这个查询几乎杀死了数据库(查询需要 20 分钟到 61 分钟之间的任何时间),在此期间 CPU 完全耗尽。
我发现为每个表运行单独的 SELECT 语句最多只需要几秒钟,并决定在应用程序级别将它们合并在一起,该应用程序级别位于不同的物理服务器上,这是一个额外的好处(下面的伪代码)。
$result1 = SELECT
`a` AS `Human readable A`,
`b` AS `Human readable B`,
`c` AS `Human readable C`,
FROM `table1`
$result2 = SELECT
`a` AS `Human readable A`,
`b` AS `Human readable B`,
`c` AS `Human readable C`,
FROM `table2`
$result3 = SELECT
`a` AS `Human readable A`,
`b` AS `Human readable B`,
`c` AS `Human readable C`,
FROM `table3`
$result4 = merge($result1, $result2, $result3)
但是,我觉得这有点不安全,因为查询可能会在这些单独的选择查询之间更新数据。有没有办法改进我的一组 select 语句查询,使其仅被视为一个事务(不需要写入),因此所有数据都将被共享读锁锁定并返回。
附加信息
我预测原始表单花费的时间要长得多,因为它花费了大量 CPU 时间重新创建/排序组合表中的索引,这是我不需要做的事情(我只需要将结果附加在一起)。
- 所有表都具有完全相同的结构
- 请注意,每个表大约有 34 个
a
ASHuman readable A
,数据被分成不同的表,因为它们涉及不同的项目。 - 此特定查询中有 20 个联合(21 个表)。
- 对数据使用 InnoDB 表。我知道这在 CPU 上比 MyIsam 更密集,但是在阅读了 MyIsam 的各种缺点之后,我不愿意切换存储引擎。
- 没有 WHERE 子句(数据已经“预先分组”,已被拆分为表)