2012-02-10 21 views
7

El usuario puede buscar por código postal (p. Ej .: L14, L15, L16) o la ubicación desde un cuadro de texto.¿Otra forma de mejorar SQL Query para evitar la unión?

Si el tipo de usuario en "Liverpool", encontrará todas las tiendas que se encuentran en "Liverpool". Si el usuario escribe en el código postal (por ejemplo, L15), buscará en todas las tiendas que realizan entregas en la zona de código postal L15.

consulte las tablas siguientes:

mysql> select * from shops; 
+----+----------+-----------+----------+ 
| id | name  | location | postcode | 
+----+----------+-----------+----------+ 
| 1 | Shop One | Liverpool | L10  | 
| 2 | Shop Two | Liverpool | L16  | 
+----+----------+-----------+----------+ 

-

mysql> select * from shops_delivery_area; 
+------------------+---------+----------+---------------+ 
| delivery_area_id | shop_id | postcode | delivery_cost | 
+------------------+---------+----------+---------------+ 
|    1 |  1 | L10  |   1.50 | 
|    2 |  1 | L11  |   0.00 | 
|    3 |  1 | L12  |   1.00 | 
|    4 |  1 | L13  |   1.00 | 
|    5 |  2 | L10  |   2.50 | 
|    6 |  2 | L16  |   0.00 | 
|    7 |  2 | L28  |   0.00 | 
+------------------+---------+----------+---------------+ 

de consultas SQL:

SELECT U.* FROM 
    ((SELECT DISTINCT shops.*, DA.delivery_cost, DA.postcode AS AreaPostcode FROM shops 
      JOIN shops_delivery_area as DA on (DA.shop_id = shops.id) 
    WHERE DA.postcode = "Liverpool") 
    UNION 
    (SELECT DISTINCT shops.*, DA.delivery_cost, DA.postcode AS AreaPostcode FROM shops 
      JOIN shops_delivery_area as DA on 
           (DA.shop_id = shops.id AND 
           DA.postcode = shops.postcode) 
    WHERE shops.location = "Liverpool")) as U 

-

Resultado - por Localización (Liverpool):

+----+----------+-----------+----------+---------------+--------------+ 
| id | name  | location | postcode | delivery_cost | AreaPostcode | 
+----+----------+-----------+----------+---------------+--------------+ 
| 1 | Shop One | Liverpool | L10  |   1.50 | L10   | 
| 2 | Shop Two | Liverpool | L16  |   0.00 | L16   | 
+----+----------+-----------+----------+---------------+--------------+ 

Resultado - por código postal (L12):

+----+----------+-----------+----------+---------------+--------------+ 
| id | name  | location | postcode | delivery_cost | AreaPostcode | 
+----+----------+-----------+----------+---------------+--------------+ 
| 1 | Shop One | Liverpool | L10  |   1.00 | L12   | 
+----+----------+-----------+----------+---------------+--------------+ 

que parezca estar funcionando correctamente ... ¿Hay otra manera de mejorar la consulta SQL más corta para evitar union o algo así?

+0

Qué razón tienes para evitar 'UNION'? PD. Creo que puede eliminar las palabras clave 'DISTINCT' porque' UNION' es la abreviatura de 'UNION DISTINCT'. – onedaywhen

Respuesta

1

Lo que elija, tenga en cuenta que el código corto no siempre es código óptimo. En muchos casos, cuando tiene una lógica lo suficientemente divergente, la unión de los resultados realmente es la opción más óptima (ya veces más limpia, programáticamente).

Dicho esto, lo siguiente o en la cláusula WHERE parece cubrir tanto sus casos ...

SELECT DISTINCT 
    shops.*, 
    DA.delivery_cost, 
    DA.postcode AS AreaPostcode 
FROM 
    shops 
INNER JOIN 
    shops_delivery_area as DA 
    ON (DA.shop_id = shops.id) 
WHERE 
    (DA.postcode = "Liverpool") 
OR 
    (DA.postcode = shops.postcode AND shops.location = "Liverpool") 
+0

¡Gracias! Entonces, ¿cuál sería la mejor opción en cuanto a rendimiento?Quédese con Union o 'OR' en la cláusula DONDE –

+0

Acabo de hacer pruebas de rendimiento ... Parece que usar 'Unión' es más rápido. –

+0

@ user791022 sayd 'Acabo de hacer pruebas de rendimiento ... Parece que usar Union es más rápido. ** Te lo dije. ** qué es más rápido dos hits de índice en el medio de una tabla o un escaneo de toda la tabla ? cuando aplicas el pensamiento de "aplicación" (reduce el código redundante, etc.) a SQL, te encuentras con problemas de rendimiento. –

0

¿Qué me estoy perdiendo? Por qué no puedes hacer

WHERE DA.postcode = "Liverpool" or shops.location = "Liverpool" 
+0

Eso no funcionaría correctamente, de lo contrario obtendrá muchas filas del mismo nombre de tiendas. Eche un vistazo a 'JOIN' cuidadosamente. –

+1

usando un 'OR' puede matar el rendimiento dependiendo de cómo se usan los índices. Por lo general, dividiré una consulta en un 'UNION' como este para evitar un 'OR' y obtendré la ganancia de rendimiento sustancial de usar un índice en cada parte de 'UNION'. –

+0

@Diego, le falta una restricción cuando es 'shops.location =" Liverpool "'. –

1

Dado que todas las tablas y columnas seleccionadas son las mismas, sólo tiene que hacer esto:

SELECT DISTINCT shops.*, DA.delivery_cost, DA.postcode AS AreaPostcode FROM shops 
      JOIN shops_delivery_area as DA on DA.shop_id = shops.id 
    WHERE (DA.postcode = "Liverpool") 
     OR (DA.postcode = shops.postcode AND shops.location = "Liverpool") 

como usted ha dicho en la respuesta de Diego, las condiciones son a poco de diferente! Por lo tanto, compensa esa diferencia en el WHERE clause.

0

favor intente esto:

SELECT DISTINCT shops.*, 
     DA.delivery_cost, 
     DA.postcode 
FROM shops 
     JOIN shops_delivery_area as DA on DA.shop_id = shops.id 
WHERE DA.postcode = "Liverpool" 
     OR (location = "Liverpool" and DA.postcode = shops.postcode)