> -----Ursprüngliche Nachricht-----
> Von: joerg.bru...@sun.com [mailto:joerg.bru...@sun.com]
> Gesendet: Dienstag, 13. Oktober 2009 15:26
> An: Skoric, Majk
> Cc: mysql@lists.mysql.com
> Betreff: Re: OR vs UNION
> 
> Majk, all,
> 
> 
> I'm no optimizer expert, but your result doesn't really surprise me.
> 
> I'll reorder your post because that makes reasoning simpler:
> 
> majk.sko...@eventim.de wrote:
> > Hi List,
> 
> First, your table:
> 
> > TABLEDEF.
> > | KTEMP | CREATE TABLE `KTEMP` (
> >   `tid` bigint(20) NOT NULL auto_increment,
> >   `kunde_id` varchar(20) collate utf8_bin NOT NULL,
> >   `buchung_id` varchar(20) collate utf8_bin NOT NULL default '0',
> >   `buchungs_kunde_id` varchar(20) collate utf8_bin NOT NULL,
> >   `veranst_id` bigint(20) NOT NULL,
> >   `rolle_nummer` int(11) default '0',
> >   `status` tinyint(1) unsigned NOT NULL,
> >   `tstamp_insert` bigint(20) NOT NULL,
> >   `tstamp_update` bigint(20) NOT NULL,
> >   `KategorienWechsel` tinyint(4) NOT NULL default '0',
> >   PRIMARY KEY  (`tid`),
> >   KEY `buchungs_kunde_id`
> (`buchungs_kunde_id`,`veranst_id`,`status`),
> >   KEY `kunde_id` (`kunde_id`,`veranst_id`,`status`)
> > ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin |
> 
> So you have two indexes which consist of three fields each, and the
> least significant two fields are the same for both indexes.
> 
> 
> You do a SELECT that fully specifies values for these two indexes,
> combining them with "OR":
> 
> >
> > mysql> explain SELECT * FROM KTEMP WHERE (buchungs_kunde_id =
> > 'dfb49c8c0b441e9f' and veranst_id = 16058 and status = 1) or
> (kunde_id=
> > 'dfb49c8c0b441e9f' and veranst_id = 16058 and status = 1);
> > +----+-------------+-------+-------------+---------------------------
> -+-
> > ---------------------------+---------+------+------+-----------------
> ---
> > ----------------------------------+
> > | id | select_type | table | type        | possible_keys
> |
> > key                        | key_len | ref  | rows | Extra
> > |
> > +----+-------------+-------+-------------+---------------------------
> -+-
> > ---------------------------+---------+------+------+-----------------
> ---
> > ----------------------------------+
> > |  1 | SIMPLE      | KTEMP | index_merge | buchungs_kunde_id,kunde_id
> |
> > buchungs_kunde_id,kunde_id | 71,71   | NULL |    2 | Using
> > union(buchungs_kunde_id,kunde_id); Using where |
> > +----+-------------+-------+-------------+---------------------------
> -+-
> > ---------------------------+---------+------+------+-----------------
> ---
> > ----------------------------------+
> > 1 row in set (0.00 sec)
> >
> > All seems fine here . Optimizer choose to use an union! This is the
> same
> > as following union query.
> 
> As an alternative, you replace the "OR" by a UNION. No real change:
> 
> >
> > mysql> explain extended (SELECT * FROM KTEMP WHERE buchungs_kunde_id
> =
> > 'dfb49c8c0b441e9f' and veranst_id = 16058 and status = 1) UNION
> (SELECT
> > * FROM KTEMP WHERE kunde_id = 'dfb49c8c0b441e9f' and veranst_id =
> 16058
> > and status = 1);
> > +----+--------------+------------+------+-------------------+--------
> ---
> > --------+---------+-------------------+------+-------------+
> > | id | select_type  | table      | type | possible_keys     | key
> > | key_len | ref               | rows | Extra       |
> > +----+--------------+------------+------+-------------------+--------
> ---
> > --------+---------+-------------------+------+-------------+
> > |  1 | PRIMARY      | KTEMP      | ref  | buchungs_kunde_id |
> > buchungs_kunde_id | 71      | const,const,const |    1 | Using where
> |
> > |  2 | UNION        | KTEMP      | ref  | kunde_id          |
> kunde_id
> > | 71      | const,const,const |    1 | Using where |
> > |NULL | UNION RESULT | <union1,2> | ALL  | NULL              | NULL
> > | NULL    | NULL              | NULL |             |
> >
> 
> Note that both queries fully specify the index values.
> 
> 
> Then, you apply Boolean logic to factor out the two identical
> predicates
> from both the "OR" alternatives:
> 
> >
> > But the following query is handled in a strange way
> >
> > mysql> explain SELECT * FROM KTEMP WHERE (buchungs_kunde_id =
> > 'dfb49c8c0b441e9f' or kunde_id= 'dfb49c8c0b441e9f') and veranst_id =
> > 16058 and status = 1;
> > +----+-------------+-------+------+----------------------------+-----
> -+-
> > --------+------+---------+-------------+
> > | id | select_type | table | type | possible_keys              | key
> |
> > key_len | ref  | rows    | Extra       |
> > +----+-------------+-------+------+----------------------------+-----
> -+-
> > --------+------+---------+-------------+
> > |  1 | SIMPLE      | KTEMP | ALL  | buchungs_kunde_id,kunde_id | NULL
> |
> > NULL    | NULL | 1040700 | Using where |
> > +----+-------------+-------+------+----------------------------+-----
> -+-
> > --------+------+---------+-------------+
> >
> > I don't get it! Maybe someone has a clue or a hint for me.
> 
> While that is equivalent from a logic point of view, it is different
> for
> the optimizer:
> You do not specify the values for any of the indexes completely,
> because
> the first term contains an "OR" over two different fields, and the
> other
> terms don't specify the most significant fields of the index.
> 
> The only way for the system to use an index would be to revert your
> change and to go back to the first statement, where the "OR" is on the
> outermost level.

Ah ok. I got it!

> 
> >
> >
> > mysql> SELECT VERSION();
> > +---------------------+
> > | VERSION()           |
> > +---------------------+
> > | 5.0.27-standard-log |
> > +---------------------+
> > 1 row in set (0.00 sec)
> 
> I don't think using a newer version would change anything, but you
> should be working on an update nonetheless. There were several
> important
> changes since that version, including security fixes.

Its on my TODO list ;)

> 
> But as 5.0 is approaching its EOL and 5.1 is GA, I hope that update
> will
> target 5.1.
> 
> 
> HTH,
> Jörg

Thanks for your time!

Majk

--
MySQL General Mailing List
For list archives: http://lists.mysql.com/mysql
To unsubscribe:    http://lists.mysql.com/mysql?unsub=arch...@jab.org

Reply via email to