与源表相比,对临时表的 SQL 查询需要双倍的时间这是正常的吗?

问题描述

我认为临时表应该比普通表快,因为我知道临时表存储在缓存中,而普通表存储在磁盘上。但如果我错了,请纠正我。无论哪种方式,如果不是这种情况,临时表比作为(数据的)精确副本的常规表慢,我想了解原因。

我创建了一个包含 1 亿行和 6 列的表格。然后我创建了一个包含所有数据的临时表(同一张表的精确副本)。但是当我在原始表上尝试特定查询时需要 23 秒,而在临时表上执行完全相同的查询需要 1 分钟。

很明显,我对“临时表存储在缓存中,因此它们必须更快”的理解是错误的。你能帮我理解为什么与普通表具有相同数据的临时表更慢吗?--- ¿它们如何存储? ¿ MysqL 是否对临时表使用不同的引擎? ¿ 优化器对临时表的作用是否不同? ¿ 常规表是否获得临时表无法获得的自动索引/分区? ¿还有其他原因吗?

为了记录,这里是普通表:

CREATE TABLE tablota (ALGO int,id_col int PRIMARY KEY,col1 float NOT NULL,col2 float NOT NULL,tipo int NOT NULL,fecha TIMESTAMP NOT NULL); 

这里我从一个 ~8GB 的​​ csv 文件中加载它(请注意,我必须使用非标准格式的字段“fecha”):

LOAD DATA INFILE "C:/ProgramData/MysqL/MysqL Server 8.0/Uploads/generador.csv"
INTO TABLE tablota
FIELDS TERMINATED BY ',' 
IGnorE 1 LInes
(ALGO,id_col,col1,col2,tipo,@fecha)
SET fecha = STR_TO_DATE(@fecha,'%d/%m/%Y %h:%i %p');

结果是 100,000,000 个条目,包含 6 列表(如果我运行 SELECT COUNT(1) FROM tablota,结果是 100M)。然后我将临时表创建为原始表的精确副本(至少在数据方面):

CREATE TEMPORARY TABLE tablota_virt 
SELECT * FROM tablota;

最后,这是对“常规表”的查询

SELECT SUM(col1) FROM tablota WHERE tipo BETWEEN 1750 AND 1800;

运行几次(超过 10 次)并且没有在服务器上打开其他应用程序(Localhost,所以我自己的 PC),需要 20-30 秒。此查询采用全表扫描计划。

这是对临时表的查询

SELECT SUM(col1) FROM tablota_virt WHERE tipo BETWEEN 1750 AND 1800;

在相同条件下(仅运行 MysqL 和至少 10 次试验),需要 50-70 秒。它还使用了全表扫描。

编辑: SHOW CREATE TABLE tablota 得到:

For tablota

对于 tablota_virt(临时的)

For tablota_virt


作为记录,我知道这绝对不是尝试优化查询的最佳方法,我知道第一种方法应该是选择正确的数据架构、正确的索引和正确的顺序,以及分区。我在这里尝试做的是纯粹测试临时表与“常规”表,没有索引、分区、其他查询的并发性或在服务器(我的 PC)中运行的其他应用程序。

解决方法

tl;博士。临时表和永久表是同一种数据库对象。临时表中唯一不同的是命名范围(本地连接)和断开连接时的自动删除。

你写道:

我认为临时表应该比普通表快,因为我知道临时表存储在缓存中,而普通表存储在磁盘上。但如果我错了,请纠正我..

你确实错了。

您向我们展示的查询需要 (tipo,col1) 上的复合索引才能最有效。无论该表是否为临时表,都是如此。您不应期望大型临时表的性能明显优于普通表。

您的查询性能数字可能取决于您进行查询时服务器 RAM 缓存中的内容。 编辑 不可能在任何特定时间确切知道服务器 RAM 缓存中的内容。对于 InnoDB 引擎来说,临时表和永久表或多或少是一样的。它们只是它必须处理的两个大型磁盘表。我认为你的问题假设你新创建的临时表应该在缓存中。将行写入任何 InnoDB 表、temp 或 perm 的操作需要将它们提交到磁盘。因此,服务器可能会将其缓存用于永久表的页面,而不是临时页面。再说一次,你不知道。

您可以尝试在临时表上创建索引。但是,太浪费了!您将让您的服务器完成索引临时表的所有工作,以便在您完成后将其删除。

首先创建如此大的临时表并没有什么好处。临时表使用与普通表相同的存储引擎,除非您在创建它们时另行指定。它们只有连接范围的名称,并在连接关闭时被删除。

您可以为临时表使用 MEMORY 存储引擎,但这可能会耗尽您的服务器 RAM 并失败。无论如何,MEMORY 表使用的 HASH 索引对于您向我们展示的那种范围查询来说并不是最佳的。

我的建议:重新考虑您的工作流程以摆脱临时表,并索引您的永久表以匹配您需要性能的查询。