【问题标题】:Need help optimizing mysql query comparing two tables需要帮助优化比较两个表的mysql查询
【发布时间】:2013-06-15 07:12:53
【问题描述】:

这是对我之前的问题link 的跟进。

一段时间过去了,所以我不确定是否需要更新那个或创建一个新的,特别是因为我的问题的参数发生了一些变化。

--

我有一个大型(简单)电话号码表(> 500 万并且还在增长)。表设置如下:

| AreaCode | Local | Created |
  • 'Local' 是 3 位区号后面的 7 位数字
  • “已创建”只是一个时间戳
  • AreaCode 和 Local 均已编入索引
  • 我曾经有一个 ID 列作为我的主键,但在我对表进行分区时删除了它。我在 AreaCode (

我正在上传数字的 csv 文件(最多 250k 行),通过 PHP 清理和清理输入,然后创建一个临时表并将数据插入其中。

在这之后,我遇到了很多麻烦。对于较小的数据大小(10k-25k 行),我真的没有任何问题。但是,当我尝试将包含 250k+ 行的临时表与我的主数据库进行比较时,需要的时间非常长。

我已经尝试了以下 2 个查询,但其中任何一个都不太走运。

使用内部连接

SELECT a.* FROM master_table a
INNER JOIN temp_table b
ON a.AreaCode = b.AreaCode
AND a.Local = b.Local;

我在一个网站上找到了这个建议并尝试了它

SELECT b.* FROM temp_table b
WHERE b.AreaCode
IN (
    SELECT a.AreaCode
    FROM master_table a
    WHERE a.AreaCode = b.AreaCode
    AND a.Local = b.Local
);

我为长长的问题道歉,但我对 mysql 的掌握很弱。

  1. 我是否因为没有主键和/或唯一键而犯了错误?由于每个电话号码都是唯一的,我不确定拥有 ID 列是否对我有好处。
  2. 我对我的主表进行分区是正确的还是这会减慢我的速度?
  3. 我的 AreaCode 和 Local 列上有索引。当我创建临时表时,我是否也应该在其中的相同列上创建索引?
  4. 请帮我解决我的查询,这样就不会花这么长时间了!!

【问题讨论】:

  • 您是否查看了查询计划输出以查看您的两个查询是否都在进行表扫描?那将是我要看的第一件事。另外,我会在临时表上放置一个索引,因为如果你不这样做,你实际上是在子查询期间强制进行表扫描。
  • 每列有单独的索引,还是(AreaCode, Local)有复合索引?
  • @TimoGeusch 那会使用解释吗?我昨天确实拉了它,我现在正试图理解它,tbh。和 ty 用于澄清临时表上的索引。我一直在这样做,但不确定是否应该这样做。
  • @Barmar 我正在使用单独的索引。这不是要走的路吗?
  • 优化连接时只能使用一个索引。如果您有单独的索引,它将选择其中一个,然后必须进行扫描以匹配另一列。如果您使用复合索引,它可以使用它同时匹配两列。

标签: mysql comparison


【解决方案1】:

回答您的问题:

  1. 我看不到您是如何使用当前索引强制执行唯一性的。您可以在areaCodelocal 上使用复合主索引来强制实现这种唯一性。我肯定会有某种主键。我会质疑您是否需要在没有areaCode 的情况下查询local 以确定您是否需要单独的索引。就个人而言,如果我要在其他表中引用该数据(例如,如果我想将电话号码与用户相关联),我可能会在这两个字段上使用自动增量主键和复合唯一索引,因为我发现它较少使用单个键时关联表很麻烦。

  2. 500 万行并不是一张那么大的表。可能为时过早进行分区。此外,根据数据库中不同区号的比例以及这些区号的访问模式,这可能不是一个好的分区方案。

  3. 如果您要使用磁盘上的临时表并加入这些大型数据集,则需要提供索引。

  4. 您有两个不同的查询在此处执行两种不同的操作。如果最终目的是将此数据插入到主表数据中,我不明白您为什么要尝试进行联接。你可以简单地按照以下方式做一些事情:

>

 INSERT INTO master_table (`areaCode`, `local`)
 SELECT SELECT `areaCode`, `local`
 FROM temp_table
 ON DUPLICATE KEY UPDATE UPDATE `created` = NOW() /* You can add this line is you want to update the time stamp */

【讨论】:

  • 你说得对,我真的不是。我对数据库结构的理解非常薄弱,所以感谢您的详细解释。在两列上使用复合主键会更有效,还是我应该使用完整的电话号码创建第三列并将其用作主键?由于我应该只拥有每个数字中的一个,这是一种可以接受的方法吗?你会在什么时候推荐使用分区?我正在阅读,如果使用得当,分区确实会有所帮助,但如果使用不当也会造成很大的伤害(我怀疑我正在这样做)。
  • 基本上,我在这里所做的是我的过程的第一步。我试图首先找到重复项,以便我可以用这些数字拍摄一个 csv 文件。然后我需要生成另一个具有唯一编号的文件。我确实需要插入新数据,但也需要保留重复信息。所以我在想的是1)比较临时表和主表,找到重复项,将这些值存储到一个数组中。 2) 运行类似于 #1 的查询来查找和存储唯一值。 3) 将新值插入主表。
  • @ahnkee 另一种可能的方法是按照我的建议将项目直接插入表中,但插入一个标志,您可以使用该标志对新添加的记录进行后处理。在处理这些记录时,您可以将标志设置回默认状态。
  • 啊,我明白了。我看到了您的建议的优点,以及它将如何帮助我消除一个步骤,甚至使我的脚本运行得更快。这可能是一个低级问题,但标志是我要创建的附加列,对吗?
  • 太棒了。谢谢你的帮助!今天将实施这些更改。将为您提供最新进展!
猜你喜欢
  • 2011-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多