大表上的连接查询非常慢(machine = Xeon 2.4 GHz,16核,64 GB RAM)

时间:2011-08-17 22:18:13

标签: python mysql sql performance

这是我的问题:

SELECT  email_data.id, email_data.source_file, email_data.report_id,
        email_data.filePath, email_data.fileName, email_data.size,
        email_data.emailID, email_data.msgID, email_data.cus, email_data.subject,
        email_data.sentto, email_data.emailFrom, email_data.hdrs, email_data.cc,
        email_data.bcc, email_data.extracted, email_data.DateTime,
        email_data.TimeStamp, email_data.OriginalDateTime, email_data.ParentID,
        email_data.reply_to, email_data.MD5Hash, email_data.duplicated,
        email_data.TimeZone, email_data.AttachName, email_data.fqdn, 
        attach_data.id, attach_data.source_file, attach_data.report_id,
        attach_data.filePath, attach_data.fileName, attach_data.size, attach_data.ext,
        attach_data.emailID, attach_data.cus, attach_data.extracted,
        attach_data.MD5Hash, attach_data.duplicated
FROM email_data 
LEFT JOIN attach_data
ON (email_data.emailID = attach_data.emailID);

两个表的组合有50k +记录(email_data有22k记录,其他有30K +记录)。

以上查询需要90分钟以上仍未完成。

这一个:

SELECT email_data.id, attach_data.id 
FROM email_data 
LEFT JOIN attach_data 
ON (email_data.emailID = attach_data.emailID);

花费2分钟22秒:

我做错了什么?似乎MySQL没有使用足够的内存来加速,而且它只使用16个核心中的1个核心。

如何配置它以使用所有可用资源?

或者我应该查询ID(如在第二个查询中)并循环+在我的代码中选择它们中的每一个?它会导致同样的结果吗?

我需要所有这些字段和所有行,我将它们转换为自定义CSV格式,以便将其导出到其他软件。

专栏:

mysql> show columns from email_data;
+------------------+----------+------+-----+---------+----------------+
| Field            | Type     | Null | Key | Default | Extra          |
+------------------+----------+------+-----+---------+----------------+
| id               | int(11)  | NO   | PRI | NULL    | auto_increment |
| source_file      | longtext | YES  |     | NULL    |                |
| report_id        | int(11)  | YES  |     | NULL    |                |
| filePath         | longtext | YES  |     | NULL    |                |
| fileName         | longtext | YES  |     | NULL    |                |
| size             | int(11)  | YES  |     | NULL    |                |
| emailID          | longtext | YES  |     | NULL    |                |
| msgID            | longtext | YES  |     | NULL    |                |
| cus              | longtext | YES  |     | NULL    |                |
| subject          | longtext | YES  |     | NULL    |                |
| sentto           | longtext | YES  |     | NULL    |                |
| emailFrom        | longtext | YES  |     | NULL    |                |
| hdrs             | longtext | YES  |     | NULL    |                |
| cc               | longtext | YES  |     | NULL    |                |
| bcc              | longtext | YES  |     | NULL    |                |
| extracted        | longtext | YES  |     | NULL    |                |
| DateTime         | char(1)  | YES  |     | NULL    |                |
| TimeStamp        | int(11)  | YES  |     | NULL    |                |
| OriginalDateTime | char(1)  | YES  |     | NULL    |                |
| ParentID         | longtext | YES  |     | NULL    |                |
| reply_to         | longtext | YES  |     | NULL    |                |
| MD5Hash          | longtext | YES  |     | NULL    |                |
| duplicated       | char(1)  | YES  |     | NULL    |                |
| TimeZone         | char(1)  | YES  |     | NULL    |                |
| AttachName       | longtext | YES  |     | NULL    |                |
| fqdn             | longtext | YES  |     | NULL    |                |
+------------------+----------+------+-----+---------+----------------+

对于attach_data

几乎相同

5 个答案:

答案 0 :(得分:3)

几乎可以肯定,attach_data.emailID缺少索引。考虑到查询引擎必须遍历每一行电子邮件数据,如果索引丢失,它必须遍历attach_data的每一行,即使找到匹配后也是如此。

您应该在查询上运行EXPLAIN以查看MySql实际上在做什么。如果索引丢失,您将进行22,000 x 30,000次比较,或进行大约6.6亿次比较以构建结果数据集。如果你的身份证是字符串,那么你可以长途跋涉。

如果您对索引attach_data.emailId进行索引,则会将比较次数减少到大约22,000 x log(30,000)或大约33万次比较。巨大的差异。使用HASH索引可以更快地进行此操作(下限为22,000次比较)。如果索引丢失,您可以在事后添加它们。

老实说,你应该考虑LIMIT跳过并取一个结果窗口。这将为您节省很多来自客户端的数据。您可能会发现这种流量可能会导致连接速度过慢(我同意另一张海报,很奇怪您没有超时)

<强>更新

圣牛。看到您对问题的更新,您绝对应该只撤回非longtext字段,遍历这些字段并一次拉回一个longtext字段。但看到你需要将一个mysql表转储到csv,我建议你研究一下mysqldump。它可以将您的数据库备份到CSV文件。

答案 1 :(得分:1)

不知道你做了什么让查询运行90分钟而超时......

检查您要加入的字段。具体来说,请查看查询(或估计的执行计划)的执行计划,以查看最昂贵的操作。

您是否加入了varchar(255)字段。 varchar(max)或类似?比较大型变速器是一项昂贵的操作。如果你可以缩短有用的领域。

关于所有这些领域:

返回较小的字段子集。如果您从sql server调用实际附件数据,那么您可能需要先执行查询以确定需要哪些附件(attach_data.PrimaryKey),而不是整行(必须将其拉入内存)。 然后,一旦获得所需的attach_data记录的PK,就可以只调用那些行所需的数据

您是否加入了非索引字段(例如,您加入主键)?向列添加索引将加快检索过程,但在执行此操作之前了解索引(例如,向列添加索引实际上会减慢数据更新/插入,并且int字段上的索引优于大范围varchars上的索引)。

答案 2 :(得分:1)

我认为你混淆了优化器。尝试为attach_data.emailID添加索引。您可以使用EXPLAIN语句来确定发生了什么。

答案 3 :(得分:1)

首先,单个查询永远不会使用多个核心(AFAIK mysql和大多数其他RDBMS)。

您的第二个查询显示mysql能够使用索引(或利用大缓存),这很好。

如果您的磁盘速度很慢且longtexts包含大量数据,那么只需将所有数据拉到内存中就可能会很慢并且会丢失内存索引页。

如果它是一个严肃的应用程序,我会切换到PostgreSQL或其他数据库作为长期解决方案。根据我的经验,mysql只能用于琐碎的任务。

答案 4 :(得分:0)

你真的希望所有的行都不在桌面上吗?如果您可以在流程中的特定时刻使用较小的查询来满足您的需求,那会更好。理想情况下,您可以在某处添加where子句。真正的滞后可能是从硬盘读取它。使用递归备份进行RAID设置可能会以某种方式加快速度,但我不确定。

您可以更改一些MySQL设置,并告诉它每个查询使用的最大内存量以及其他一些选项。

http://dev.mysql.com/doc/refman/5.0/en/memory-storage-engine.html