Question

I have a problem with the performance of a query. I have the following:

SELECT DISTINCT anuncios.id, precios.precio
FROM anuncios
LEFT JOIN precios ON ( (
precios.idcentroanuncio = anuncios.idcentro
AND anuncios.tipoubicacion = 'centropropio'
AND precios.tipocentroanuncio = 'centro'
) )
GROUP BY anuncios.id
LIMIT 0 , 30 

that spends 0.001 seg. On the other hand I have this one, very similar:

 SELECT DISTINCT anuncios.id, precios.precio
FROM anuncios
LEFT JOIN precios ON ( 
(
precios.idcentroanuncio = anuncios.id
AND anuncios.tipoubicacion = 'centropropio'
AND precios.tipocentroanuncio = 'centro'
) )
GROUP BY anuncios.id
LIMIT 0 , 30 

that also spends the same time, more or less. The problem is when I combine both queries into this one:

 SELECT DISTINCT anuncios.id, precios.precio
FROM anuncios
LEFT JOIN precios ON ( (
precios.idcentroanuncio = anuncios.idcentro
AND anuncios.tipoubicacion = 'centropropio'
AND precios.tipocentroanuncio = 'centro'
)
OR (
precios.idcentroanuncio = anuncios.id
AND anuncios.tipoubicacion = 'centropropio'
AND precios.tipocentroanuncio = 'centro'
) )
GROUP BY anuncios.id
LIMIT 0 , 30 

Here the execution time multiplies by 100.

Theese are both tables desciption:

Precios:

+-------------------+------------------+------+-----+---------+----------------+
| Field             | Type             | Null | Key | Default | Extra          |
+-------------------+------------------+------+-----+---------+----------------+
| id                | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| usuario           | varchar(40)      | NO   | MUL | NULL    |                |
| tipocentroanuncio | varchar(50)      | NO   |     | NULL    |                |
| idcentroanuncio   | int(10) unsigned | NO   | MUL | NULL    |                |
| unidades          | float            | NO   |     | NULL    |                |
| tipounidades      | varchar(15)      | NO   |     | NULL    |                |
| precio            | float            | NO   |     | NULL    |                |
| otrosdatosprecio  | varchar(100)     | NO   |     | NULL    |                |
| principal         | int(1) unsigned  | NO   |     | NULL    |                |
+-------------------+------------------+------+-----+---------+----------------+

anuncios:

+------------------+------------------+------+-----+---------------------+----------------+
| Field            | Type             | Null | Key | Default             | Extra          |
+------------------+------------------+------+-----+---------------------+----------------+
| id               | int(10) unsigned | NO   | PRI | NULL                | auto_          |
+------------------+------------------+------+-----+---------------------+------

and this is the explain of the query:

id  select_type     table   type    possible_keys   key     key_len     ref     rows Extra
1   SIMPLE  anuncios    ALL     NULL    NULL    NULL    NULL    1048578     Using temporary; Using filesort

1   SIMPLE  precios     index   idcentroanuncio     idcentroanuncio     156 NULL    30  Using index

What am I doing wrong? Is it logical this time increase combining two querys that run fast independently?

Was it helpful?

Solution

Yes. You have learned the or can really mess up execution plans. Try using union instead:

SELECT a.id, p.precio
FROM anuncios a LEFT JOIN
     precios p
     ON p.idcentroanuncio = a.idcentro AND
        a.tipoubicacion = 'centropropio' AND 
        p.tipocentroanuncio = 'centro'
UNION
SELECT a.id, p.precio
FROM anuncios a LEFT JOIN
     precios p
     ON p.idcentroanuncio = a.id AND
        a.tipoubicacion = 'centropropio' AND
        p.tipocentroanuncio = 'centro'
LIMIT 0 , 30;

Some notes and then a better query. First, you don't need distinct when you have group by. Second, this version doesn't need group by or distinct, because the union takes care of making the values distinct.

For performance, you may be able to take a different route. Try this:

select p.idcentroanuncio, p.price
from precios p
where p.tipocentroanuncio = 'centro' and
      (exists (select 1
               from annuncios a
               where p.idcentroanuncio = a.id and a.tipoubicacion = 'centropropio'
              ) or
       exists (select 1
               from annuncios a
               where p.idcentroanuncio = a.idcentro and a.tipoubicacion = 'centropropio'
              )
      );

This may eliminate the need for the distinct. And the subqueries can each take advantage of an index: annuncios(id, tipoubicacion) and annuncios(idcentro, tipoubicacion).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top