【问题标题】:How can i make this mysql query more efficient and run faster?我怎样才能使这个 mysql 查询更高效并运行得更快?
【发布时间】:2015-03-16 23:09:35
【问题描述】:

这是我的 mysql 查询(3 个嵌套选择语句):

SELECT * FROM emotions 
WHERE 
( randomid IN 
     ( 
           SELECT idpost 
           FROM p_n_relation 
           WHERE idnetwork IN 
           (
                 SELECT id 
                 FROM networks 
                 WHERE name = 'Babblenow' 
                       AND isActive = 1 
                       AND isDeleted = 0
          ) 
       AND isActive = 1 AND isDeleted = 0 
   )   AND isActive = 1 
       AND isDeleted =0 
       AND onid = '0' AND type = 0 
)ORDER BY rating DESC

每个表的情绪、p_n_relations 和网络包含大约 10k 行。
此查询的执行时间超过 30 秒,并在运行时挂起服务器!
有没有更有效的方法来做我想做的事情?大公司如何在几秒钟内做到这一点?

编辑 - 确切地说:
p_n_relations : 5774networks : 9emotions : 427 中的行数 还有这个Query took 125.6770 sec

我的数据库结构:
情绪表、网络表、P_n_relation 表依次排列。
http://imgur.com/bmEEavH,d3iE6Lg,twXMWU9

【问题讨论】:

  • 你试过 MySQL 中的 EXPLAIN 语句了吗?
  • 你的 MySQL 版本是多少?因为 MySQL
  • 不抱歉,我从未听说过!
  • @Fenistil 最新版本是 5.6.22(Beta 5.7.5),所以...我在哪里可以获得 MySQL 6.0?
  • 停止使用 sub select 并开始使用 JOINS 作为启动器。

标签: mysql sql performance time time-complexity


【解决方案1】:

试试这个:

SELECT emotions.* FROM emotions
LEFT JOIN p_n_relation ON (p_n_relation.idpost = emotions.randomid)
LEFT JOIN networks ON (networks.id = p_n_relation.idnetwork)
WHERE 
(networks.name='Babblenow') AND (networks.isActive = 1) AND (networks.isDeleted = 0) AND
(p_n_relation.isActive = 1) AND (p_n_relation.isDeleted = 0) AND
(emotions.isActive = 1) AND (emotions.isDeleted = 0) AND (emotions.onid = '0') AND (emotions.type = 0)
ORDER BY emotions.rating DESC

根据您发布的表结构,我建议对emotions.randomid 和p_n_relation.idpost(现在为varchar(40) 和varchar(50))使用相同的字段类型。除此之外,还对emotions.randomid、p_n_relation.idpost、networks.id 和p_n_relation.idnetwork 进行了标记。正如其他人建议的那样,尝试在networks.name上建立索引。之后,尝试逐步构建您的查询。

首先,从情绪中选择情绪。*但不要使用地点和时间。它应该很快,如果不是你的 MySQL 配置有一些大问题。

SELECT emotions.* FROM emotions;

如果速度快,加入p_n_relation就可以了,但不要用where。

SELECT emotions.*, p_n_relation.* FROM emotions
LEFT JOIN p_n_relation ON (p_n_relation.idpost = emotions.randomid);

如果你有正确的索引,它也应该很快。如果不是,请尝试解释它:

EXPLAIN SELECT emotions.*, p_n_relation.* FROM emotions
LEFT JOIN p_n_relation ON (p_n_relation.idpost = emotions.randomid);

您可以阅读 here 关于 EXPLAIN 输出的信息,但您也可以将其发布到您的问题中。

所以如果它仍然很快,加入第三张桌子就可以了:

SELECT emotions.*, p_n_relation.* FROM emotions
LEFT JOIN p_n_relation ON (p_n_relation.idpost = emotions.randomid)
LEFT JOIN networks ON (networks.id = p_n_relation.idnetwork);

测试、测量,然后开始逐步包含 WHERE 部分。如果某处性能下降,您应该对其进行调查(可能是错误或缺失的索引、字段类型或 MySQL 本身的某些问题)。

【讨论】:

  • 准确地说,这个查询用了 28.5680 秒,由 PhpMyadmin 测量。
  • 为了给出更好的答案,我们需要所有的表结构、索引以及您想要获得的内容。我可以在 1-2 秒内在 Core2Duo 上加入 600K+ 行表。它只取决于数据结构和良好的索引。
  • 太棒了!如何向您提供我的数据库结构?
  • SQL 转储结构? Phpmyadmin / 打开表格 / 导出选项卡 / 导出结构。或者您可以截屏,然后将图像上传到某处,然后将它们链接到此处。
  • 一般来说,向 where 子句(isActive、isDeleted ...)中的字段添加索引会提高性能。
【解决方案2】:

转换为连接,颠倒连接顺序:

SELECT DISTINCT e.*
FROM networks n
JOIN p_n_relation r ON r.idnetwork = n.id
JOIN emotions e ON e.randomid = r.idpost
WHERE n.name = 'Babblenow' 
AND n.isActive = 1 
AND n.isDeleted = 0

此表顺序是最佳的,因为您的标准都在网络表上。优化器应该识别这一点并自动更改连接顺序,但我通过经验发现优化器可以是密集的。

创建索引(如果它们不存在):

create index networks_name on networks(name);
create index  p_n_relation_idnetwork on (p_n_relation(idnetwork);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-17
    • 1970-01-01
    • 1970-01-01
    • 2013-08-29
    • 2021-04-17
    • 1970-01-01
    • 2021-08-01
    相关资源
    最近更新 更多