为什么MySQL'插入... select ...'比单独选择要慢得多?

时间:2013-10-09 10:12:36

标签: mysql performance temp-tables insert-into mysql-cluster

我正在尝试将查询结果存储在临时表中以供进一步处理。

create temporary table tmpTest
(
    a FLOAT,
    b FLOAT,
    c FLOAT
)
engine = memory;

insert into tmpTest
(
    select a,b,c from someTable
    where ...
);

但由于某种原因,插入需要一分钟,而单独的子选择只需要几秒钟。为什么将数据写入临时表而不是将其打印到我的SQL管理工具的输出需要这么长时间?

更新 我的设置: MySQL 7.3.2集群用 8 Debian Linux ndb数据节点 1 SQL节点(Windows Server 2012)

我正在运行select on的表是一个ndb表。

我试图找出,如果执行计划在使用'insert into ..'时会有所不同,但它们看起来是一样的: (抱歉格式化,stackoverflow没有表格)

id  select_type     table       type    possible_keys   key     key_len ref                 rows        Extra
1   PRIMARY         <subquery3> ALL     \N              \N      \N      \N                  \N          \N
1   PRIMARY         foo         ref     PRIMARY         PRIMARY 3       <subquery3>.fooId   9747434     Using where
2   SUBQUERY        someTable   range   PRIMARY         PRIMARY 3       \N                  136933000   Using where with pushed condition; Using MRR; Using temporary; Using filesort
3   MATERIALIZED    tmpBar      ALL     \N              \N      \N      \N                  1000        \N

CREATE TABLE ... SELECT也很慢。 47秒与5秒没有表插入/创建。

3 个答案:

答案 0 :(得分:3)

我在上面写了一条评论,然后偶然发现这是一种解决方法。

这将完成你想要做的事。

SELECT * FROM aTable INTO OUTFILE '/tmp/atable.txt';
LOAD DATA INFILE '/tmp/atable.txt' INTO TABLE anotherTable;

请注意,这样做意味着以某种方式管理/ tmp表。如果您尝试将数据选择为已存在的OUTFILE,则会出现错误。因此,您需要生成唯一的临时文件名。然后运行某种类型的cron工作来清理它们。

我猜INFILE和OUTFILE的行为有所不同。如果有人能够对这里发生的事情有所了解来解释mysql的行为,我将不胜感激。

d

这是一种比使用INFILE / OUTFILE更好的方式。

SET TRANSACTION ISOLATION LEVEL READ COMMITTED;    插入表格    SELECT ... FROM ...

以下是相关帖子:

How to improve INSERT INTO ... SELECT locking behavior

答案 1 :(得分:1)

我遇到了同样的问题,正在玩实际解决它的子查询。 如果select具有大量行,则插入数据需要很长时间。 例如:

INSERT INTO b2b_customers (b2b_name, b2b_address, b2b_language)
SELECT customer_name, customer_address, customer_language
FROM customers
WHERE customer_name LIKE "%john%"
ORDER BY customer_created_date DESC
LIMIT 1

将INSIT与INSERT数据结合使用不是一个好选择。因此,您可以使用2个单独的查询来获取数据和插入,或者您可以使用子查询。 例如:

INSERT INTO b2b_customers (b2b_name, b2b_address, b2b_language)
SELECT * FROM (
SELECT customer_name, customer_address, customer_language
FROM customers
WHERE customer_name LIKE "%john%"
ORDER BY customer_created_date DESC
LIMIT 1
) sub1

这将是一个快速的解决方案,而无需更改您的脚本。

所以我不确定为什么运行子查询需要0.01秒,运行插入需要60秒。我没有限制就获得了1000多个结果。在我的例子中,子查询将性能从60秒提高到0.01秒。

答案 2 :(得分:0)

原因与计算机的读写方式以及临时文件的工作方式有关。 Select正在读取硬盘驱动器上索引文件中的数据,而insert正在使用临时文件并正在写入该文件。需要更多RAM,这样做更加困难。 至于为什么需要一分钟,我不确定,但我认为代码可能有点不正确,所以这会有所贡献。