2012-02-22 60 views
5

MySQL服务器版本:5.1.41在Ubuntu 10.04MySQL的观点或VS IN子句

修改一些查询,当我遇到在MySQL的活动的差异来了,想知道它的原因。

基本上我正在创建一个视图。查询视图时,结果集相同 但是,对于IN子句,读取的行数与对OR子句而言是不同的。下面下面是一个简单的例子:

CREATE TABLE country ( 
    id_country int(11) NOT NULL AUTO_INCREMENT, 
    name varchar(50) NOT NULL, 
    PRIMARY KEY (id_country) 
) ENGINE=InnoDB; 

INSERT INTO country (name) VALUES ('A'), ('B'), ('C'), ('D'), ('E'), ('F'), ('G'), ('H'); 

CREATE TABLE status ( 
    id_status int(11) NOT NULL AUTO_INCREMENT, 
    id_country int(11) NOT NULL, 
    status tinyint(4) NOT NULL, 
    PRIMARY KEY (id_status) 
) ENGINE=InnoDB; 
ALTER TABLE status ADD INDEX (id_country); 
ALTER TABLE status ADD FOREIGN KEY (id_country) REFERENCES test.country (id_country) ON DELETE RESTRICT ON UPDATE RESTRICT ; 

INSERT INTO status(id_country, status) VALUES 
(1,0), (2,1), (3,0), (4,1), (5,0),(6,1), (7,0), (8,1); 

CREATE ALGORITHM=MERGE VIEW view_country 
AS 
    SELECT c.*, s.id_status, s.status 
    FROM country c JOIN status s ON c.id_country = s.id_country; 

2.解释下图显示不同的行数的语句解析

mysql> EXPLAIN EXTENDED SELECT * FROM view_country WHERE id_country IN (1, 2, 3)\G; 
*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: c 
     type: range 
possible_keys: PRIMARY 
      key: PRIMARY 
     key_len: 4 
      ref: NULL 
     rows: 3 
    filtered: 100.00 
     Extra: Using where 
*************************** 2. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: s 
     type: ref 
possible_keys: id_country 
      key: id_country 
     key_len: 4 
      ref: test.c.id_country 
     rows: 1 
    filtered: 100.00 
     Extra: 
2 rows in set, 1 warning (0.00 sec) 

使用或条款

mysql> EXPLAIN EXTENDED SELECT * FROM view_country WHERE id_country = 1 OR id_country = 2 OR id_country = 3\G; 
*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: s 
     type: ALL 
possible_keys: id_country 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 8 
    filtered: 37.50 
     Extra: Using where 
*************************** 2. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: c 
     type: eq_ref 
possible_keys: PRIMARY 
      key: PRIMARY 
     key_len: 4 
      ref: test.s.id_country 
     rows: 1 
    filtered: 100.00 
     Extra: 
2 rows in set, 1 warning (0.00 sec) 

如果你看一下“行“在这两个查询中 - 它们的总和有所不同

查询有OR子句与IN相比读取的行数减少,这会加起来用于巨大的表和连接。

有人能帮我理解为什么这样吗?

谢谢你的时间。

+0

始终相同,但不同的结果? – 2012-02-22 18:40:28

+0

@Marcus - 我是sry我不明白这个问题 - 如果你的意思是我每次都得到一致的结果集,每次解析的行数也是一致的 - 那么答案是肯定的 – naveen 2012-02-23 17:39:22

+0

@Marcus Adams - 有一个复制粘贴我的错误 - 我纠正了它。问题不是关于不同的结果集 - 结果集是相同的 - 但读取的行数与IN或OR不同 - 请告诉我,如果您无法重现它 - 我在服务器版本上:5.1 – naveen 2012-02-23 22:04:00

回答

1

请注意,执行计划有很多事情要做你的索引的状态,你的表的大小。即使对于类似的查询,MySQL可能执行的方式也不同,有时MySQL甚至可能会猜错。

与JOIN视图肯定复杂的东西,所以你的SELECT语句并不那么简单。不要惊讶MySQL为IN和OR选择不同的执行计划。

在第一个查询的情况下,MySQL已经选择对两个查询使用索引,这会导致EXPLAIN中特定且准确的行数。

但是,在第二个查询中,MySQL选择扫描状态表中的所有行。这是有道理的,因为行数很少,MySQL无论如何都不得不访问表,因为没有覆盖索引会返回所有需要的行。如果第二个查询实际上并不比第一个查询快,我不会感到惊讶。另外请注意,EXPLAIN中的行数(对于扫描)是估计值,因此在分析查询时请考虑这一点。

第一个查询必须执行6次查找,而第二个查询只需要在非常短的表扫描后执行3次查找。

MySQL有很多技巧,有时仅限于非常特定的场景,以根据当前索引和行数来优化您的查询。有记录的案例在哪里,for similar queries, MySQL will take two different approaches and end up with the same execution path。还有其他两种完全不同的执行计划会导致类似性能的情况,这就是其中的一种情况。

无论如何,我希望这可以告诉你为什么会有差异,但只要结果相同,表现相似,就没有什么值得关注的。

在某些情况下,正如我刚才所说的,MySQL只是不会做出最好的猜测,然后您可以使用索引提示和自然联接等工具。就你而言,我认为MySQL表现得很好。

要研究的性能和执行计划更检查出两个以下站点:

+0

感谢您的解释Marcus - 作为一种良好的做法,我想我需要经历任何复杂的连接查询并查看mysql如何选择索引 – naveen 2012-03-01 04:04:59

0

如果我理解正确,你得到的结果是一样的,你想知道'OR'和'IN'关于速度及其工作方式的区别。

如果是这样,比我想你的问题是这一个可能重复:IN vs OR in the SQL WHERE Clause

+0

我相信OP表示使用“IN”而不是“OR”的结果是不同的 – 2012-02-22 18:49:07

+0

好吧,那么我没有正确理解他的问题。我会认为结果是一样的。 – Honnes 2012-02-23 07:27:02

+0

@ZackMacomber,来自问题:*“结果集是相同的”*。 – 2012-02-23 13:41:29