2017-07-01 30 views
1

目前我正在开发一个项目,需要我为我的用户编写一个API。到目前为止,我写了下面的SQL语句和测试它在我的本地在我的PHP:对于另一个mysql版本,SQL查询执行速度较慢?

SELECT topquery.kind_id, 
     topquery.image, 
     topquery.id, 
     userquery.user_name 
FROM `order` AS topquery, 
    `user` AS userquery 
WHERE userquery.user_id = topquery.user_id 
    AND topquery.id IN 
    (SELECT MIN(id) 
    FROM `order` AS mainquery 
    WHERE user_id != '$vUserId' 
     AND id NOT IN 
     (SELECT order_id 
      FROM history 
      WHERE user_id = '$vUserId') 
     AND kind_id NOT IN 
     (SELECT o.kind_id 
      FROM history h 
      INNER JOIN `order` o ON h.order_id = o.id 
      WHERE h.user_id = '$vUserId') 
     AND actions > 0 
     AND kind = '1' 
    GROUP BY kind_id) 
ORDER BY vip DESC 
LIMIT 35 

此查询需要在我的本地约0.5秒,并采取〜1.4秒我的服务器上。

现在我的问题: 有没有可能是SQL查询的速度可以为每个MySQL版本有什么不同? 或者我的查询不够“优化”了吗?

+1

你尝试检查此查询与解释(当地生产ENVS)? – Neodan

+1

速度在不同系统上变化的原因有很多。它可能是软件版本,MySQL服务器配置,RAM大小/ spped,CPU,磁盘速度,操作系统,数据大小等。我们不可能缩小它,绝对没有关于这些事情的信息(即使这样很难)。 –

回答

0

是的,这将是不同的,因为SQL的每一个版本具有不同的调整,以优化或者代码路径或算法的处理速度。我认为最新版本会比以前更快。

0

偏离主题的意见,但我想这样的格式的注释是不够

您使用WHERE子句中的连接谓词开始查询

FROM `order` AS topquery, 
    `user` AS userquery 
WHERE userquery.user_id = topquery.user_id 

,更深入到查询你使用INNER JOIN语法。那么为什么不这样做呢?

FROM `order` AS topquery, 
INNER JOIN `user` AS userquery ON userquery.user_id = topquery.user_id 

坚持只使用显式连接。不要让自己在from子句中的表之间使用逗号。不要“混合和匹配”连接语法,这会导致维护问题和可能的错误。

0

在这里,我概括的诊断为你的情况,然后才能确定该速度是否仍是实际的问题:

  1. 网络。我不知道这是纯粹从SQL执行的还是网络时间。您的网络通话将导致开销。

  2. 这取决于你的服务器是什么,但如果你的环境相匹配,它几乎总是肯定,因为在比你的本地主机服务器数据库实质上更多的数据。

一个在公司范围内具有共享开发服务器的组件加起来的是,有人可能会放一些数据上有你每隔一段时间,所以大家不必须所有内容复制到他们的机器工作具有实际大小的数据集。更多的数据=更多的工作=需要更长的时间,就这么简单。

  1. 您的数据库模式存在差异。如果你不想在一个命令中重建你的数据库,你可能已经在localhost上添加了一个索引并且忘了它。您可以使用模式工具来获取localhost和数据库之间的差异。我喜欢SQLYog。我认为Mysql工作台也是如此。

  2. 您的硬件存在差异。也就是说你的服务器是一个带有4MB内存的486。

0

差异服务器

是的,性能不同的MySQL版本之间的变化之间的性能。原因是整个软件可能会发生变化,包括MySQL优化器,它会计算查询将执行的计划。

几个因素,我会决定的MySQL版本是否是根本原因之前检查是:

  1. 硬件 - 你在你的本地主机和您的服务器上有不同的硬件? CPU,内存,硬盘等
  2. 分配资源 - 您是否在不同服务器上的my.cnf/my.ini配置文件中为MySQL实例提供了不同的内存分配?如果是这样,它会严重影响MySQL实例的性能。
  3. 缓存 - 也许查询被其中一台服务器上的MySQL实例缓存。我建议重新启动MySQL实例以确保缓存清除,然后运行查询并比较执行时间。
  4. 数据量 - 您的本地主机和第二台服务器的数据量是否有所不同?如果是这样,它可以显着影响查询执行时间。

查询性能

另外,我看了您的查询,它看起来像它可以更好的优化。

(我以前EverSQL SQL Query Optimizer得到建议 - 免责声明,我EverSQL的共同创始人和谦卑地提供这些建议):

  1. 您可以替换子选择(这是不好的性能)带有INNER JOIN的IN子句。
  2. 您可以使用LEFT JOIN替换NOT IN子句中的子查询,这可以提高性能。
  3. 此外,当您有复杂的子查询时,可以考虑将它们拆分为临时表并加入到这些表中。最大的好处是你可以索引临时表中的列,并加入它,一旦会话结束,它将被删除。
  4. 确保您添加相关索引(根据列中的数据分布及其基数)。确保索引符合条件的顺序。

这是查询将如何看起来像优化后:

create table temp as 
SELECT 
      o.kind_id 
     FROM 
      history h 
      INNER JOIN `order` o ON h.order_id = o.id 
     WHERE 
      h.user_id = '$vUserId'; 

CREATE INDEX kind_id on temp(kind_id); 

create table temp2 as 
SELECT 
     MIN(id) as id 
    FROM 
     `order` AS mainquery 
     left join history h on mainquery.id=h.order_id 
     left join temp t on mainquery.kind_id=t.kind_id 
    WHERE 
     user_id != '$vUserId' 
     AND h.order id is null 
     and t.kind_id is null 
     AND actions > 0 
     AND kind = '1' 
    GROUP BY 
     kind_id;  

CREATE INDEX id on temp2(id); 

SELECT 
    topquery.kind_id, 
    topquery.image, 
    topquery.id, 
    userquery.user_name 
FROM 
    `order` AS topquery, 
    `user` AS userquery, 
    temp2 AS temp 
WHERE 
    userquery.user_id = topquery.user_id 
     AND topquery.id = temp.id 
ORDER BY vip DESC 
LIMIT 35 
+0

'最大的好处是你可以索引临时表中的列,加入它,一旦会话完成,它将被删除。因此,在应用条件之后,您将执行lexing + I/O,将其存储到临时结构中,然后再次执行lex + I/O,这比仅执行整个事件的速度快?你的索引策略是..索引一切在哪里?你知道什么是基数吗?我可以看到你通过回答MySQL问题来推广自己的工具,但是你提供的是FALSE知识。我不会让你失望,但请 - 确保你是正确的。 –

+0

那么,MySQL优化手册第8.2.2节指定优化器可以选择优化IN子句到EXIST子句或使用实际化,这实际上是在内存中创建一个临时表(如果返回到磁盘存储,则返回if表格变得太大了,这通常是这种情况),这可能是索引或可能不是。 根据我对TB级数据和复杂查询的经验,在这种情况下手动应用此更改并且不信任优化器,性能更好,可以提供高达500%的性能改进。 太长了,再添加一条评论。 – Tomer

+0

显然,通过使用临时表,我们为查询添加了一些开销。但是,这个开销可以忽略不计,因为创建表只需要几个毫秒的时间,而不需要MySQL实现它。 关于索引建议 - 我同意它需要重新编写(已完成)。 我试图提供优质和有用的建议,但如果有什么我对社区规则做了让我知道,我会从中学习。 – Tomer