如何优化此mysql查询:
SELECT *
FROM messages
WHERE toid='".$mid."'
AND fromid='".$fid."'
OR (toid='".$fid."' AND fromid='".$mid."')
AND subject != 'something'
order by id ASC LIMIT 0,5
我需要在一个页面中的用户之间获取消息。此查询ID占用了大量时间和服务器资源。可以用其他方式完成吗?
感谢。
答案 0 :(得分:2)
如上所述,查询可能背叛了实际意图。似乎所需的条件是
WHERE ( ( toid='".$mid."' AND fromid='".$fid."' )
OR (toid='".$fid."' AND fromid='".$mid."')
)
AND subject != 'something'
但是,如上所述,查询将仅使用第二个(toid和fromid)子句应用主题条件 注意,在上面,内括号是无关的;从来没有那么通常是一个好主意,包括它们以更明确地显示预期的表达。
在任何一种情况下,由于OR子句和NOT EQUAL谓词,此查询是一个“硬[er]”查询解析。 OR子句通常使服务器合并来自两个子查询的结果(尽管其他策略是可能的)。 NOT EQUAL谓词不能通过索引查找来解析(但是覆盖索引在某些情况下确实有帮助),因为它将行程保存到主表/其他索引以评估手头的行是否满足谓词)
独立于这个可能的逻辑问题,添加索引将有多个键可以帮助解决这个问题。我想建议如下:
还包括主题的索引的兴趣是允许通过部分扫描索引来解析查询,而不是必须查找主题。此索引将用作此查询的覆盖索引。
请注意,添加索引会降低INSERT,UPDATE和DELETE操作的性能。
编辑:关于(toid,fromid,subject)索引的可用性
首先,我们承认我们只需要一个建议的索引,即如果我们有(toid,fromid,subject)索引,那么(toid,fromid)将是多余的(尽管如果主题是相对的,可能更有效率)长栏)
这就是说,查询在主题上使用NOT EQUAL谓词的事实不必排除在(toid,fromid,subject)索引中使用主题数据。原因是主题上的[不等于]条件可以在索引中解析(不需要匹配/合并或查找,即类似于某些“覆盖”逻辑)
答案 1 :(得分:1)
正如zerkms指出的那样,在这种情况下你不能为主题做索引。在评论中查看他的建议。
为两个ID添加一个索引:
CREATE INDEX ids_index ON messages (fromid, toid);
并将查询拆分为两个。
答案 2 :(得分:1)
在货币对上添加一个索引(toid
,fromid
)。这将允许它使用索引来查找相关消息并加快查询速度。注意,各列上的索引可能仍然会留下许多要扫描的消息,即那些消息往/来自其中一个人到另一个人。使用该对将索引扫描找到的消息限制为两个人之间的消息。
答案 3 :(得分:1)
鉴于您希望有一些逻辑来阻止用户向自己发送消息,或许这样:
WHERE toid IN ($mid, $fid) AND fromid IN ($mid, $fid) AND subject <> 'something'
在(toid, fromid)
上放一个索引,我觉得这应该很好。