[英]Combine multiple Selects without Union or Union All
我有一个庞大的查询,该查询曾经对很多表(每个表有成千上万行)执行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)
但是,我觉得这有点不安全,因为查询可能会更新这些单独的选择查询之间的数据。 有没有一种方法可以改善我的选择语句查询集,使其仅作为一个事务处理 (无需写操作),因此所有数据将被共享的读取锁锁定并返回。
附加信息
我预计原始表单会花费更长的时间,因为它花费大量的CPU时间来重新创建/排序组合表中的索引,而我不需要这样做(我只需要将结果附加在一起)。
a
AS Human readable A
a
AS。由于数据与不同的项目相关,因此数据被分为不同的表。 考虑到您的约束,最好的调用是在发出每个连续的SELECT
之前显式地锁定表:
SET autocommit=0; -- optional, but this is where and how you must start the transaction if you need one
LOCK TABLES t1 READ, t2 READ, t3 READ;
SELECT a FROM t1;
SELECT a FROM t2;
SELECT a FROM t3;
UNLOCK TABLES; -- beware: implicit COMMIT
除非有某种法律要求将这些数据保存在多个表中,否则您确实应该坚持验证所有这些表合并到一个表中。
我以为我会通过代码示例提供两种可能的解决方案及其各种好处。 解决方案之一是从RandomSeed的答案中“窃取”:
if ($READING_ONLY_INNODB_TABLES)
{
/**
* - Since these tables are innodb, we can make use of its 'REPEATABLE READ'
* isolation level
* - Locking the entire tables directly is slightly faster, but this method
* allows us to have a consistent view of the database without implementing
* ANY locks (which would block other processes).
* It may be easier to think of them as locking as this results in the same
* result in terms of consistency (innodb even handles phantom reads at this level)
* - MyIsam does not support REPEATABLE READ, hence this cannot be used for it
*/
$query =
'START TRANSACTION WITH CONSISTENT SNAPSHOT;'. # --auto sets "SET autocommit=0"
$queries_string . # --This is the series of selects
'COMMIT;';
}
else
{
/**
* This is a lower resource intensive, 'generic' way (works with MyISAM) that will wait until it can read lock
* all the tables before reading. This way we should 'force' a
* 'repeatable read'/consitent view.
*/
$query =
'SET autocommit=0;'. # starts the transaction
'LOCK TABLES ' . $lock_tables_string . ';' . # Automatically commits anything before this
$queries_string . # This is the series of selects from the tables we just locked
'UNLOCK TABLES;'; # commits a transaction if any tables currently have been locked with LOCK TABLES
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.