Please provide SHOW CREATE TABLE for the two tables.

Plan A:
Would the anti-UNION problem be solved by hiding the UNION in a subquery?  The 
outer query would simply return what the UNION found.

Plan B:
Insert every row twice into expression_expression -- (e1,e2) and also (e2,e1).
Then, you need only one index into that table, and you don't need to UNION (or 
the LEFT JOINs).

Plan C:
Do something with a VIEW.  Caution:  Performance _may_ be even worse.

> -----Original Message-----
> From: brian [mailto:mysql-l...@logi.ca]
> Sent: Tuesday, July 03, 2012 12:50 PM
> To: mysql@lists.mysql.com
> Subject: Re: alternative to slow query
> 
> On 12-07-03 02:18 PM, Stillman, Benjamin wrote:
> > Not sure why it  wouldn't show primary as a possible key then...
> 
> Yes, that seems rather strange.
> 
> 
> >  From your first email:
> >
> > *************************** 1. row ***************************
> >              id: 1
> >     select_type: SIMPLE
> >           table: e
> >            type: ALL
> > possible_keys: NULL
> >             key: NULL
> >         key_len: NULL
> >             ref: NULL
> >            rows: 95127
> >           Extra:
> >
> >
> > I'd be curious to see the explain from this:
> >
> > select id, lang, term from expression where id = (insert a random,
> > valid id value here);
> >
> > Does it use a key then? Or at least show primary as a possible key?
> 
> mysql db_lexi > EXPLAIN SELECT id, term, lang_id FROM expression WHERE
> id = 223363\G
> *************************** 1. row ***************************
>             id: 1
>    select_type: SIMPLE
>          table: expression
>           type: const
> possible_keys: PRIMARY
>            key: PRIMARY
>        key_len: 8
>            ref: const
>           rows: 1
>          Extra:
> 1 row in set (0.00 sec)
> 
> 
> Here's the query again, with some of the stuff I'd removed for clarity.
> There are still some other fields missing here but they involve 2 left
> joins on other tables.
> 
> mysql db_lexi > EXPLAIN SELECT e.id, e.lang_id, e.term
>      -> FROM (expression AS e)
>      -> LEFT JOIN expression_expression AS ee1
>      -> ON ee1.expression1_id = e.id AND ee1.deleted_at = 0
>      -> LEFT JOIN expression_expression AS ee2
>      -> ON ee2.expression2_id = e.id AND ee2.deleted_at = 0
>      -> WHERE (ee2.expression1_id = 223363 OR ee1.expression2_id =
> 223363)
>      -> AND e.original_id IS NULL
>      -> AND e.deleted_at = 0\G
> *************************** 1. row ***************************
>             id: 1
>    select_type: SIMPLE
>          table: e
>           type: ref
> possible_keys: original_id_idx,deleted_at_idx
>            key: original_id_idx
>        key_len: 9
>            ref: const
>           rows: 60560
>          Extra: Using where
> *************************** 2. row ***************************
>             id: 1
>    select_type: SIMPLE
>          table: ee1
>           type: ref
> possible_keys: expression1_id_idx
>            key: expression1_id_idx
>        key_len: 8
>            ref: db_lexi.e.id
>           rows: 1
>          Extra:
> *************************** 3. row ***************************
>             id: 1
>    select_type: SIMPLE
>          table: ee2
>           type: ref
> possible_keys: expression2_id_idx
>            key: expression2_id_idx
>        key_len: 8
>            ref: db_lexi.e.id
>           rows: 1
>          Extra: Using where
> 3 rows in set (0.00 sec)
> 
> I presume that e.id is not being used because I'm not specifically
> querying against it. Instead, I'm using expression_expression's FKs.
> 
> Which gives me an idea. I can add expression a 2nd time to the FROM
> clause:
> 
> mysql db_lexi > EXPLAIN SELECT e.id, e.lang_id, e.term
>      -> FROM (expression AS e, expression AS e_pk)
>      -> LEFT JOIN expression_expression AS ee1
>      -> ON ee1.expression1_id = e.id AND ee1.deleted_at = 0
>      -> LEFT JOIN expression_expression AS ee2
>      -> ON ee2.expression2_id = e.id AND ee2.deleted_at = 0
>      -> WHERE
>      -> (ee1.expression2_id = e_pk.id AND ee2.expression1_id = 223363)
>      -> OR (ee1.expression1_id = e_pk.id AND ee1.expression2_id =
> 223363)
>      -> AND e.original_id IS NULL
>      -> AND e.deleted_at = 0\G
> *************************** 1. row ***************************
>             id: 1
>    select_type: SIMPLE
>          table: ee1
>           type: ALL
> possible_keys: expression2_id_idx,expression1_id_idx
>            key: NULL
>        key_len: NULL
>            ref: NULL
>           rows: 106191
>          Extra: Using where
> *************************** 2. row ***************************
>             id: 1
>    select_type: SIMPLE
>          table: e
>           type: eq_ref
> possible_keys: PRIMARY,original_id_idx,deleted_at_idx
>            key: PRIMARY
>        key_len: 8
>            ref: db_lexi.ee1.expression1_id
>           rows: 1
>          Extra:
> *************************** 3. row ***************************
>             id: 1
>    select_type: SIMPLE
>          table: ee2
>           type: ref
> possible_keys: expression2_id_idx
>            key: expression2_id_idx
>        key_len: 8
>            ref: db_lexi.ee1.expression1_id
>           rows: 1
>          Extra: Using where
> *************************** 4. row ***************************
>             id: 1
>    select_type: SIMPLE
>          table: e_pk
>           type: ALL
> possible_keys: PRIMARY
>            key: NULL
>        key_len: NULL
>            ref: NULL
>           rows: 121120
>          Extra: Range checked for each record (index map: 0x1)
> 4 rows in set (0.00 sec)
> 
> 
> But this doesn't feel like an elegant solution. Regardless, I'm still
> seeing the query take ~2.5sec. I'm just looking into the "Range checked
> for each record" msg now. Perhaps this is the right direction but
> requires a little tweaking.
> 
> 
> I don't understand why deleted_at_idx is also not used, though. Perhaps
> because I'm only looking for values of 0? Regardless, that doesn't seem
> to be the heart of the problem.
> 
> BTW, I inherited the DB, so can't be sure whether I've missed anything.
> 
> --
> MySQL General Mailing List
> For list archives: http://lists.mysql.com/mysql
> To unsubscribe:    http://lists.mysql.com/mysql


--
MySQL General Mailing List
For list archives: http://lists.mysql.com/mysql
To unsubscribe:    http://lists.mysql.com/mysql

Reply via email to