在 MySQL 和 PHP 中使用多表和 LEFT JOIN 查询非常慢

Posted

技术标签:

【中文标题】在 MySQL 和 PHP 中使用多表和 LEFT JOIN 查询非常慢【英文标题】:Extremely slow query with multitables and LEFT JOIN, both in MySQL and PHP 【发布时间】:2013-04-05 06:17:25 【问题描述】:

我的问题是我添加的行越多,检索 SQL 查询结果所需的时间就越多。我不是在谈论大量的行(在 10,000 - 80,000 之间)。一开始我需要几毫秒才能从查询中检索结果,昨天我最多需要 3 分钟才能显示 50 行,但从今天开始它就达到了最大值:

致命错误:第 247 行的 C:\wamp\apps\phpmyadmin3.5.1\libraries\dbi\mysqli.dbi.lib.php 中的最大执行时间超过 300 秒

找不到问题所在(我是 SQL 新手)。我已经为此苦苦挣扎了两个月。我已经尝试了所有可以在互联网上找到的解决方案(包括这里)来加快速度,我什至更改了主机、phpMyAdmin、mysql、httpd.config、iPV6 等的配置文件。但是因为没有这很奏效,我回滚了所有更改,创建了一个新数据库,并在其中添加了一个唯一的 uuid 以左连接数据库中的表

但它仍然像龟树懒一样缓慢!

我不确定这是 PHP、MySQL、apache 本地服务器 (WAMPP) 的问题,还是 SQL 级别的数据结构问题(我没有主键,也不是唯一键,也不是索引集,因为我不知道如何使用然后)。

让我给你一些关于我正在做什么以及我正在尝试做什么的背景信息。

我每天都会进行几次 API 调用,以获取针对特定搜索引擎的产品和搜索的不同广告的排名位置。我使用 Python 解析 API 对象,同时也将数据注入 MySQL 数据库。

每个页面结果都有一个包含 50 个产品广告的列表,这些广告按与搜索引擎的相关性排序。这个排名位置每天都在变化。每个排名位置列表是根据搜索引擎中使用的关键字('key')生成的。尽管每个产品每天都可以更改其属性,但它始终具有相同的唯一 ID ('ad_id')。例如,产品 ad_id = a001 可能显示它今天的访问量比前一天增加了 200 次,或者它的卖家可能更改了他/她的“别名”。

我在排名位置列表(排名数据库)中生成 uuid 字符串,然后我将该 uuid 附加到其他数据库。

所以这些是我的表格(见下面的链接)。为了清楚起见,我过度简化了。表格仅显示前 3 行,请注意第三行的 RANKINGS、ITEMS 和 USERS 显示不同的日期(这是因为我每天都会更新数据库)。

http://oi49.tinypic.com/11ceidz.jpg

我的数据结构实际上是这样的(基于过于简化的示例):

排名

c_id int(11),不为空,AUTO_INCREMENT ad_id varchar(20),不为空 rank int(3) not null 卖家int(20),不为空 键 varchar(30),不为空 日期时间戳,CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP uuid varchar(36)

用户

c_id int(11),不为空,AUTO_INCREMENT 卖家int(20),不为空 别名 varchar(30),不为空 日期时间戳,CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP uuid varchar(36)

项目

c_id int(11),不为空,AUTO_INCREMENT ad_id varchar(20),不为空 title varchar(30),不为空 subtitle varchar(30), null 访问 int(11),不为空 日期时间戳,CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP uuid varchar(36)

这是我的查询

选择rankings.key、rankings.rank、items.visits、users.seller、users.alias、rankings.ad_id、items.title、rankings.date

来自排名

在rankings.uuid = items.uuid 上LEFT JOIN 项目

LEFT JOIN users ON rankings.seller = users.seller

WHERE 排名.key = 'apple'

GROUP BY rankings.date,rankings.rank

我做错了什么?任何帮助/提示将不胜感激!并提前感谢您的帮助!

编辑:如果我删除 GROUP BY 行并添加 LIMIT 0, 50 查询的结果将只需要几毫秒...但是有大量重复的行!如果 Limit 0, 500 = 仅 4 秒。

第二次编辑Scorpi0成功了!!!请参阅下面的他/她的答案。

【问题讨论】:

如果您不在表上使用索引,则每个简单的选择都必须读取相关表的全部内容。我建议你阅读一些关于数据库、表和索引的文档或教程。 谢谢,jap1968!话虽如此,您认为我需要再次重做数据库吗?还是只是将索引添加到我当前数据库的表中?顺便说一句,如果我不使用最后一行(GROUP BY),查询结果会在几毫秒内出现。但是有重复! – 再次感谢。 【参考方案1】:

哇!

我没有主键,也没有唯一键,也没有设置索引,因为那时我不知道如何使用

真的吗?那就学吧!! 没有索引,查询在 O(n^3) 中运行,有 3 个表。使用索引,它将在 O(log n) 中运行。

直接跑吧

CREATE INDEX idxrankginsuuid ON rankings(uuid);
CREATE INDEX idxrankingsseller ON rankings(seller);
CREATE INDEX idxrankingskey ON rankings(key);

CREATE INDEX idxitemsuuid ON items(uuid);

CREATE INDEX idxuserseller ON users(seller);

您会注意到性能提高了。

如果不知道主键和索引是如何工作的,就无法执行 SQL。

【讨论】:

如果您在伦敦,您一定会得到享受!!!有用!是的,我知道我应该学习,但我不知道如何或从哪里开始。你看,我不是程序员,也没有计划成为一名程序员,因为我的领域与编程相去甚远(尽管我最近学习 Python 的基本编程只是为了应对挑战并解析我的 API 数据)。谢谢一百万! P.S.我没有足够的声望来支持你。但在这里,我的 +1 票是金子。 请记住,当您的查询中有“columnName = something”时,创建索引几乎总是一个好主意。 好!再次非常感谢。无法投票给你是多么的不公平。但也许这就是想法:阻止像我这样的新手从像你这样享有盛誉的海报中获得宝贵的帮助。 天哪!两年后我忘记接受你的回答了!!抱歉,我认为这与我在 *** 中的第一个问题有关(编辑:似乎系统让我再次投票赞成你的答案!)。【参考方案2】:

服务器处理查询的时间过长,因为它不是一个简单的查询。您可以优化您的 MySQL 查询和数据库的结构以尝试加快进程,或者,如果您不能,通过在开头添加 set_time_limit(0); 将 PHP 脚本的最大执行时间更改为无限制脚本。

【讨论】:

谢谢菲利普!顺便说一句,如果我不使用最后一行(GROUP BY),查询结果会在几毫秒内出现。但有重复! 哦,忘了说..更改最大执行时间的想法很好,但还不够,因为仅仅 6 天后就需要 100 秒。如果我尝试这样做一年,我将花费大约 100 分钟的 SQL!而在 PHP 中需要更多的时间!

以上是关于在 MySQL 和 PHP 中使用多表和 LEFT JOIN 查询非常慢的主要内容,如果未能解决你的问题,请参考以下文章

php mysql多表查询id重复

多表关联查询语法?

在多表列中具有多个术语的简单 PHP 过滤器

MYSQL多表查询问题,left join的使用问题求教

来自多表和计数的 mysql group_concat

记一次mysql多表查询(left jion)优化案例