【问题标题】:MySQL Performance in OR operatorOR 运算符中的 MySQL 性能
【发布时间】:2017-03-14 11:31:10
【问题描述】:

这是我的桌子:

CREATE TABLE `e_relationship` (
`OID` int(11) NOT NULL AUTO_INCREMENT,
`E_E_OID` int(11) NOT NULL,
`E_E_OID2` int(11) NOT NULL,
`REL_DISPLAY` text NOT NULL,
`APP_OID` int(11) NOT NULL,
`META_OID` int(11) NOT NULL,
`STORE_DATE` datetime NOT NULL,
`UID` int(11) DEFAULT NULL,
PRIMARY KEY (`OID`),
KEY `Left_Entity` (`E_E_OID`),
KEY `Right_Entity` (`E_E_OID2`),
KEY `Meta_Left` (`META_OID`,`E_E_OID`),
KEY `Meta_Right` (`META_OID`,`E_E_OID2`)
) ENGINE=InnoDB AUTO_INCREMENT=310169 DEFAULT CHARSET=utf8;

以下查询耗时约2.5-3ms,结果集为1290行,表中总行数为1008700:

SELECT * FROM e_relationship WHERE e_e_oid=@value1 OR e_e_oid2=@value1

这是EXPLAIN的结果:

id: 1
select_type: SIMPLE
table: e_relationship
type: index_merge
possible_keys: Left_Entity,Right_Entity
key: Left_Entity,Right_Entity
key_len: 4,4
ref: NULL
rows: 1290
Extra: Using union(Left_Entity,Right_Entity); Using where

我想加快这个查询,因为这在我的系统中非常关键,我不确定我是否在 mysql 中遇到某种瓶颈,因为记录的数量已经超过一百万,并且会想了解其他可能的提高性能的策略。

【问题讨论】:

  • 考虑到行数和数据分布,2.5-3 毫秒似乎是合理的。
  • 你可以试试IN算子。
  • 首先(正如 Mihai 所说),对于 1M 记录表来说,3ms 是相当不错的响应时间。其次,尝试监控系统(CPU、内存、磁盘),看看是否有任何达到高百分比。
  • 根据解释,MySQL 已经为您的查询使用了索引合并优化,这是您在不使用显式联合的情况下获得的最快速度。您在对已删除答案的评论中说工会速度较慢。这是作为开发人员所能得到的。从此时起,将任务交给 DBA,后者可以微调 MySQL 设置以提高查询性能。不过,我倾向于同意 2-3ms 似乎是相当快的性能的观点。
  • 您的查询已按原样优化,3ms 是一个不错的结果。如果您不需要所有列并添加覆盖索引,则可以保存表查找(要对其进行测试,请尝试select id from 而不是select * from),否则,这取决于外部因素:您如何调用查询(例如在 php 中使用准备好的语句),运行多少/什么其他查询,以及您的整体数据库性能(主要是:服务器价格)。估计:对于 1M 行(如果 text 列不太大),您的查询直接在 MySQL 中在具有足够内存的空闲(中途)cpu 上运行,应该只显示 0.000 秒。

标签: mysql indexing innodb


【解决方案1】:

有时 MySQL 无法优化 OR 查询。在这种情况下,您可以使用UNION 将其拆分为两个查询:

SELECT * FROM relationship WHERE e_e_oid = @value1
UNION
SELECT * FROM relationship WHERE e_e_oid2 = @value2

每个子查询都会使用适当的索引,然后将结果合并。

但是,在简单的情况下,MySQL 可以自动执行此转换,并且它正在您的查询中执行此操作。这就是EXPLAIN 输出中的Using union 的含义。

【讨论】:

  • 这需要更长的时间
【解决方案2】:

有一个E_E_OIDs 的表。每个e_relationship 将有(最多)2 行。那么

SELECT ...
    FROM eeoids AS ee
    JOIN e_relationship AS er ON er.ooid = ee.oid

然后从 2 列更改为 1 列。并去掉 2 个索引。

OR 的效果是否比UNION 更快。

(剩下的细节留给读者。)

类比

假设一个人有多个电话号码(座机、手机、工作等),我想根据一个电话号码查找他的记录。所以,我建立了一个phone:personID 对的表,并在phone 上建立索引。然后我做

SELECT ...
    FROM Phones AS nums
    JOIN Persons AS x ON x.personID = nums.personID
    WHERE nums.phone = '123-555-1212'

注意:Persons 表中没有电话号码。

您的E_E_OID 就像我的phone

【讨论】:

  • 加入会不会适得其反?
  • JOIN可能ORUNIONindex merge的开销更少。
  • 但是JOIN 不是替代品而是补充品,当然我还需要E_E_OIDs 表上的ORindex merge
  • 您在查找一个 OID吗?还是两个?
  • 我需要通过E_E_OIDE_E_OID2进行过滤
猜你喜欢
  • 2015-07-08
  • 2021-02-27
  • 2014-12-26
  • 2012-05-15
  • 1970-01-01
  • 1970-01-01
  • 2012-12-03
  • 2010-10-23
相关资源
最近更新 更多