我有一个大量的查询,用于在很多表(每个表有数千行)上执行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时间在组合表中重新创建/排序索引,这是我不需要做的事情(我只需要将结果附加在一起)
a
AS Human readable A
,数据被分成不同的表,因为它们与不同的项目有关。答案 0 :(得分:0)
考虑到你的约束,最好的调用是在发出每个连续的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
除非有某种法律要求将这些数据保存在多个表中,否则你应该坚持要验证将所有这些表合并到一个表中。
答案 1 :(得分:0)
我想我会通过代码示例提供两种可能的解决方案及其各种好处。其中一个解决方案是从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
}