2011-07-11 10 views
18

Necesitaré representar la ubicación de algunos eventos y estoy diseñando el esquema de la base de datos para esta aplicación. Tengo dos enfoques para la presentación de la ubicación:Esquema de la base de datos: representando la ubicación

enfoque 1: 4 tablas:

  • Países
  • Unidos
  • ciudades
  • Ubicaciones (en lugar Tengo clave externa a country_id, state_id y city_id)

enfoque 2: 1 mesa:

  • Ubicaciones y simplemente hay campos país, estado, ciudad que se almacenan como texto (no de identidad para extranjeros)

Qué enfoque le recomendaría? el primero ayudará a eliminar posibles nombres diferentes de, p. el mismo país (ee.uu., estados unidos, etc.) y podría ser útil para proporcionar sugerencias al escribir en cuadros de texto que probablemente serán obligatorios.

Sin embargo, el segundo enfoque parece que permitirá que todo sea mucho más simple y debería reducir el número de consultas a la base de datos.

¿Cuál crees que es mejor? ¿Sabes cuáles son las mejores prácticas en este caso? P.ej. ¿Cómo es que algunos portales grandes también necesitan algo como ubicación (por ejemplo, foursquare, etc.)? Afaik facebook usa el segundo enfoque, pero ... Quiero escuchar sus opiniones y posiblemente razones por las cuales elegiría un enfoque sobre otro.

Gracias!

+0

alguna sugerencia? – Bart

+0

¿Qué motor? MySQL? ¿Oráculo? DB9? SqlLite? –

+0

¿Importaría significativamente? Si es así, MySQL, pero si pudieras señalar cuál sería la diferencia en caso de, p. Oracle, eso también podría ser útil ... – Bart

Respuesta

17

Enfoque # 1:

Ésta es una buena solución si quieres un buen normalized database. Puede administrar todas sus tablas fácilmente, pero deberá tener 3 combinaciones izquierda/interna cuando consulte la ubicación. Supongo que todo está indexado correctamente para que no tenga problemas con el rendimiento, ya que estas tablas serán relativamente pequeñas (país y estados) y de tamaño mediano para Ciudades (si solo desea todas las ciudades para un país específico solamente). Si desea TODAS las ciudades del mundo, esa tabla será enorme y podría tener problemas de rendimiento en algún momento si no indexa o no se une a la tabla correctamente.

Como todo está en la base de datos, no tiene que cambiar el código si necesita agregar, actualizar o eliminar un registro.

Si necesita agregar, actualizar o eliminar cualquier registro, esta solución será muy fácil de mantener. Si necesita actualizar un nombre (por ejemplo, el nombre de la ciudad), todos los registros se actualizarán a la vez.

Las consultas serán más rápidas de ejecutar si mira por ciudad o estado será rápido, entonces una simple combinación de la izquierda para obtener el nombre hará el truco.

Enfoque # 2:

personalmente no recomiendo esto porque para el mantenimiento no es la mejor solución. Si algún día necesita recuperar datos basados ​​en una ciudad, su consulta puede ejecutarse lentamente si no se indexa correctamente. Si indexa el país, estado, ciudad, entonces será más rápido para la búsqueda (pero más lento que el primer enfoque, ya que varchar es más lento que int para la indexación). Además, aumenta el riesgo de errores para los nombres, por ejemplo: New York VS newyork VS New Yrok.

Además, si necesita actualizar el nombre de una ciudad, tendrá que volver a recuperar todos los registros que tengan ese nombre y luego actualizar todos estos registros. Que puede llevar mucho tiempo.

por ejemplo: UPDATE ubicaciones SET city = 'Nueva York' donde city = 'newyork'; * Nota: También si tiene Erratas, que tendrá que validar todos los registros para asegurarse de actualizar todos los registros

Aquí es un esqueleto en base a sus necesidades (el uso de MySQL) para la aproximación # 1:

CREATE TABLE `countries` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `name` varchar(200) NOT NULL DEFAULT '', 
    PRIMARY KEY (`id`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

CREATE TABLE `states` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `name` varchar(200) NOT NULL DEFAULT '', 
    `fk_country_id` int(10) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`id`), 
    KEY `fk_country_id` (`fk_country_id`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

CREATE TABLE `cities` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `name` varchar(200) NOT NULL DEFAULT '', 
    `fk_state_id` int(10) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`id`), 
    KEY `fk_state_id` (`fk_state_id`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

CREATE TABLE `locations` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `name` varchar(200) NOT NULL DEFAULT '', 
    `fk_country_id` int(10) NOT NULL DEFAULT '0', 
    `fk_state_id` int(10) NOT NULL DEFAULT '0', 
    `fk_cities_id` int(10) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`id`), 
    KEY `fk_country_id` (`fk_country_id`), 
    KEY `fk_state_id` (`fk_state_id`), 
    KEY `fk_cities_id` (`fk_state_id`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

/* This table should not have fk_country_id and fk_state_id since they are already in their respective tables. but for this requirement I will not remove them from the table */ 

SELECT locations.name AS location, cities.name AS city, states.name AS state, countries.name AS country from locations INNER JOIN cities ON (cities.id = fk_cities_id) INNER JOIN states ON (states.id = locations.fk_state_id) INNER JOIN countries ON (countries.id = locations.fk_country_id); 
+-------------------+---------------+----------+---------------+ 
| location   | cty   | state | country  | 
+-------------------+---------------+----------+---------------+ 
| Statue of Liberty | New York City | New York | United States | 
+-------------------+---------------+----------+---------------+ 
1 row in set (0.00 sec) 

EXPLAIN: 
+----+-------------+-----------+--------+----------------------------------------+---------+---------+-------+------+-------+ 
| id | select_type | table  | type | possible_keys       | key  | key_len | ref | rows | Extra | 
+----+-------------+-----------+--------+----------------------------------------+---------+---------+-------+------+-------+ 
| 1 | SIMPLE  | locations | system | fk_country_id,fk_state_id,fk_cities_id | NULL | NULL | NULL | 7174 |  | 
| 1 | SIMPLE  | cities | const | PRIMARY        | PRIMARY | 4  | const | 1 |  | 
| 1 | SIMPLE  | states | const | PRIMARY        | PRIMARY | 4  | const | 1 |  | 
| 1 | SIMPLE  | countries | const | PRIMARY        | PRIMARY | 4  | const | 1 |  | 
+----+-------------+-----------+--------+----------------------------------------+---------+---------+-------+------+-------+ 

Ahora Actualización:

UPDATE states SET name = 'New York' WHERE ID = 1; //using the primary for update - we only have 1 New York City record in the DB 
Query OK, 0 rows affected (0.00 sec) 
Rows matched: 1 Changed: 1 Warnings: 0 

Ahora si miro todos mis ubicaciones para esa ciudad, todos dirán: Nueva York

Para la aproximación # 2:

CREATE TABLE `locations` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `name` varchar(200) NOT NULL DEFAULT '', 
    `fk_country_id` varchar(200) NOT NULL default '', 
    `fk_state_id` varchar(200) NOT NULL default '', 
    `fk_cities_id` varchar(200) NOT NULL default '', 
    PRIMARY KEY (`id`), 
    KEY `fk_country_id` (`fk_country_id`), 
    KEY `fk_state_id` (`fk_state_id`), 
    KEY `fk_cities_id` (`fk_state_id`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 


SELECT location, city, state, country FROM locations; 
+-------------------+---------------+----------+---------------+ 
| location   | city   | state | country  | 
+-------------------+---------------+----------+---------------+ 
| Statue of Liberty | New York City | New York | United States | 
+-------------------+---------------+----------+---------------+ 

Ahora Actualización:

UPDATE locations SET name = 'New York' WHERE name = 'New York City'; // can't use the primary key for update since they are varchars 
Query OK, 0 rows affected (1.29 sec) 
Rows matched: 151 Changed: 151 Warnings: 0 

Ahora si miro todos mis ubicaciones para esa ciudad, no todos van a decir: Nueva York

Como puede ver, demoraron 1.29 segundos (sí, es rápido) pero todos los registros que tienen "Nueva York" se actualizaron, pero tal vez haya errores de ortografía o malos nombres, etc. ...

Conclusión: Por esta razón, prefiero seguir con el primer enfoque.

Nota: El país y los Estados rara vez cambian. Tal vez pueda tenerlos en su código y no hacer referencia a ellos desde la base de datos. Esto ahorrará 2 INNER JOIN de la consulta y ellos en tu código. Simplemente recuperas el ID del país o estado (lo mismo si necesitas crear un cuadro desplegable HTML).

Además, puede pensar en almacenar en caché estos países y estados utilizando memcached, APC, reddis o cualquier otro que prefiera.

4

Ir con # 1, # 2 no está normalizado, lo que puede causar problemas.

Cuestiones relacionadas