有没有更好更高效的 MySql 查询
Posted
技术标签:
【中文标题】有没有更好更高效的 MySql 查询【英文标题】:Is there a better MySql query that's more efficient 【发布时间】:2021-11-01 18:09:40 【问题描述】:我在网络搜索的帮助下建立了一个查询,但是对于我拥有的大型数据集来说效率不高。我设置了 10 天前运行的查询,但它还没有完成。我也不知道它实际上已经走了多远。我很确定 ORDER BY 部分不是必需的,我不知道它为流程增加了多少。
INSERT INTO search_table (TEXT_ID, UPRN, SOURCE_ID)
SELECT t.TEXT_ID, UPRN, s.SOURCE_ID FROM origin_table stc
INNER JOIN text_source t ON stc.INDEX_TEXT = t.SOURCE_TEXT
INNER JOIN index_source s ON stc.SOURCE_COL = s.SOURCE_COL
GROUP BY t.TEXT_ID, s.SOURCE_ID
ORDER BY t.TEXT_ID, s.SOURCE_ID
我运行了一个解释查询,结果如下:
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | s | ALL | (NULL) | (NULL) | (NULL) | (NULL) | 6 | Using temporary; Using filesort |
1 | SIMPLE | t | ALL | (NULL) | (NULL) | (NULL) | (NULL) | 2627372 | Using join buffer (flat, BNL join)" |
1 | SIMPLE | stc | ALL | (NULL) | (NULL) | (NULL) | (NULL) | 39603700 | Using where; Using join buffer (incremental, BNL join) |
对于优化此查询的任何帮助或建议表示赞赏。我非常愿意更多地了解正在发生的事情以及如何改进它。
编辑:有人问我查询的实际数据和目的。
我需要一种方法来快速查找主数据集中使用的关键字。已确定关键字及其位置。相同的关键字出现很多很多次,并且它们可能出现在主数据集中 6 列中的任何 1 列中。主数据集仅包含一个索引,即主键。我遇到的另一个问题是每个数据库的大小限制为 1Gb。我可以拥有 100 个最大 1Gb 的数据库,但不能拥有 1 个 100Gb 的数据库。
我的目标基本上是在自己的数据库中创建一个可以在需要时查询的索引,提供指向实际主记录的指针(以及它以后可能位于哪个数据库中)。或者,假设我将主数据库拆分为
数据方面:
text_source SOURCE_TEXT 基本上是一组在主数据集中找到的关键字。有大约 250 万个关键字。
index_source SOURCE_COL 是主数据集中包含的 6 列的列表。因此只有 6 行。
origin_table 是一个由 4 列组成的表,一个 PrimaryKey,SEARCH_TEXT 是关键字,SOURCE_COL 标识关键字的来源,UPRN 是最初找到数据的唯一主键。 SEARCH_TEXT 和 SOURCE_COL 都是文本字段。有近 4000 万行,每行指定关键字的位置。
目标 search_table 基本上就是上面的源表,去掉了重复的数据并用适当的键替换它
CREATE TABLE `origin_table` (
`PrimaryKey` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`SEARCH_TEXT` text DEFAULT NULL,
`UPRN` bigint(20) unsigned DEFAULT NULL,
`SOURCE_COL` tinytext DEFAULT NULL,
PRIMARY KEY (`PrimaryKey`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=39845281 DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC
CREATE TABLE `search_table` (
`PrimaryKey` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`INDEX_TEXT` int(10) unsigned DEFAULT NULL,
`UPRN` bigint(20) unsigned DEFAULT NULL,
`SOURCE_COL` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`PrimaryKey`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3
CREATE TABLE `index_source` (
`SOURCE_ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`SOURCE_COL` tinytext DEFAULT NULL,
PRIMARY KEY (`SOURCE_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb3
CREATE TABLE `text_source` (
`TEXT_ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`INDEX_TEXT` tinytext DEFAULT NULL,
PRIMARY KEY (`TEXT_ID`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2686936 DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC
【问题讨论】:
样本数据和查询应该做什么的解释会有所帮助。也就是说,带有一些连接的简单group by
很难优化,除非您可以消除聚合。
您没有使用任何密钥。如果您必须通过column
订购,则必须对order by
子句进行索引。为每个表提供show create table
。
@GordonLinoff 我已经添加了关于我打算做什么的解释。我不知道我是否需要 group by,我假设它是为了避免重复。
请提供4个表的SHOW CREATE TABLE
、3个源表的大小(GB)、RAM大小以及innodb_buffer_pool_size
和join_buffer_size
的值。我不知道是缺少一些索引,还是内存不足或其他原因。
@basha04 我想我的目标是创建一个索引。在帖子中添加了有关表格的更多信息。同样,我不确定是否需要 order by 子句,只要记录分开,订单就无关紧要,因为我可以索引产品。在运行查询之前创建索引是否有益?查询完成后,origin_table 将是多余的。
【参考方案1】:
“从不”使用TINYTEXT
,它在功能上等同于VARCHAR(255)
,但有一些缺点。
SOURCE_COL
和 INDEX_TEXT
有时被声明为 INT UNSIGNED
,有时被声明为 TINYTEXT
——这种不一致可能会导致意外。很可能它导致了这里糟糕的表现。
GROUP BY
在技术上不正确。 (参见ONLY_FULL_GROUP_BY
)因为UPRN
。
并将 innodb_buffer_pool_size
从微小的 259K 更改为 16G。
【讨论】:
SOURCE_COL 和 INDEX_TEXT 在原始表中是 TINYTEXT,但在最终表中它们成为键值。我可以只删除 GROUP BY 和 ORDER BY 吗?关于 TINYTEXT 的好提示,看起来很简单! @AdamSlade - 将 INT 称为SOURCE_ID
和 TEXT_ID
会更容易混淆。我冒昧地更改了您的问题。以上是关于有没有更好更高效的 MySql 查询的主要内容,如果未能解决你的问题,请参考以下文章