Проблема с условием в запросе

phprus

Moderator
Команда форума
Проблема с условием в запросе

Есть 3 таблицы:
1) geo_countries:
code - код страны
name

2) geo_regions:
country - код страны
region - код региона
name
(В этой таблице у каждой записи уникальны пары значений в полях country и region)

3) geo_worldcities:
country - код страны
cityname
accentcityname
region - код региона
latitude
longitude

Нужно выбрать все записи у которых geo_worldcities.cityname == 'ЧТО-ТО', попутно выбирая соответствующие названия стран и регионов.
А теперь непосредственно к проблеме. У записи в таблице geo_worldcities поле region может иметь значение '00' в этом случае вместо значения geo_regions.name нужно выбирать пустую строку.

Скажите пожалуйста можно ли это сделат ь одним запросом и если да то как?

Пока я составил следующий запрос (в нем нет проверок на geo_worldcities.region == '00'):

SELECT geo_countries.name as country_name,
geo_regions.name as region_name,
geo_worldcities.*
FROM `geo_countries`, `geo_regions`, `geo_worldcities`
WHERE
(geo_worldcities.country = geo_regions.country AND geo_worldcities.region = geo_regions.region) AND
geo_worldcities.country = geo_countries.code AND geo_worldcities.cityname = 'ЧТО-ТО'
 

phprus

Moderator
Команда форума
bgm
А немного подробнее можно? Или ссылку где про это можно почитать на русском, а то в английской документации я практически ничего не понял.
 

phprus

Moderator
Команда форума
Wicked
Спасибо. Попробую разобраться.

-~{}~ 03.07.06 22:55:

Реализовал следующим образом:
SELECT geo_countries.name as country_name,
geo_regions.name as region_name,
geo_worldcities.*
FROM `geo_countries`, `geo_worldcities`
LEFT JOIN geo_regions ON
(
geo_worldcities.country = geo_regions.country
AND
geo_worldcities.region = geo_regions.region
)
WHERE
geo_worldcities.country = geo_countries.code
AND
geo_worldcities.cityname = 'ЧТО-ТО'

Работает так как в таблице geo_regions у поля region не может быть значения 00.

-~{}~ 04.07.06 12:59:

Реализация работает, но есть некоторые проблемы с индексами. В общем вот:

У нас имеются следующие индексы:
1) geo_countries:
code - PRIMARY
name - INDEX

2) geo_regions:
country
region
name - INDEX
и индекс по 2-м полям country region

3) geo_worldcities:
Код:
Имя ключа      Тип      Количество элементов  Поле
PRIMARY        PRIMARY 	1000  	              id
accentcityname INDEX    1000                  accentcityname
region         INDEX    27                    region
country        INDEX    3                     country
cityname       INDEX    1000                  cityname
countryregion  INDEX    41                    country region
Вот что говорит EXPLAIN:
Код:
id  	 select_type  	 table  	 type  	 possible_keys  	 key  	 key_len  	 ref  	 rows  	 Extra
1 	SIMPLE 	geo_worldcities 	ALL 	accentcityname,country,cityname,countryregion 	NULL 	NULL 	NULL 	1000 	Using where
1 	SIMPLE 	geo_countries 	eq_ref 	PRIMARY 	PRIMARY 	2 	links.geo_worldcities.country 	1 	 
1 	SIMPLE 	geo_regions 	ref 	country 	country 	4 	links.geo_worldcities.country,links.geo_worldcitie... 	19
Запрос:
SELECT geo_countries.name AS country_name, geo_regions.name AS region_name, geo_worldcities . *
FROM `geo_countries` , `geo_worldcities`
LEFT JOIN geo_regions ON ( geo_worldcities.country = geo_regions.country
AND geo_worldcities.region = geo_regions.region )
WHERE geo_countries.code = geo_worldcities.country
AND (
geo_worldcities.accentcityname = 'ЧТО-ТО'
OR geo_worldcities.cityname = 'ЧТО-ТО'
)

На сколько я понимаю этот запрос совсем не использует индесы таблицы geo_worldcities.
Подскажите пожалуйста почему.
 

bgm

 
Если я правильно понял задачу, то вот такой запрос будет более правильным:

SELECT
    c.name as country_name, r.name as region_name, w*
FROM
    geo_worldcities 'w'
LEFT JOIN
    geo_regions 'r' ON (w.region=w.region)
LEFT JOIN
    geo_countries 'c' ON (w.country=c.code)
WHERE
    w.cityname='ЧТО-ТО'
 

phprus

Moderator
Команда форума
bgm
Вы поняли правильно, спасибо за помощь.

Но вопрос с индексами остался. А именно если запрос такой:
Если использовать такой запрос (ваш, но в котором везде подставлены имена таблиц) (только одно условие в секции WHERE):
[sql]SELECT geo_countries.name AS country_name, geo_regions.name AS region_name, geo_worldcities.*
FROM geo_worldcities
LEFT JOIN geo_regions ON ( geo_worldcities.region = geo_regions.region AND geo_worldcities.country = geo_regions.country)
LEFT JOIN geo_countries ON ( geo_worldcities.country = geo_countries.code )
WHERE geo_worldcities.cityname = 'ЧТО-ТО'
[/sql]
то используется индекс по полю cityname таблицы geo_worldcities, но стоит добавить еще одно условияе в WHERE то ни индекс по полю cityname , ни по полю accentcityname не используются. После модификации запрос имеет вид:
[sql]SELECT geo_countries.name AS country_name, geo_regions.name AS region_name, geo_worldcities.*
FROM geo_worldcities
LEFT JOIN geo_regions ON ( geo_worldcities.region = geo_regions.region AND geo_worldcities.country = geo_regions.country)
LEFT JOIN geo_countries ON ( geo_worldcities.country = geo_countries.code )
WHERE
geo_worldcities.cityname = 'ЧТО-ТО'
OR
geo_worldcities.accentcityname = 'ЧТО-ТО'[/sql]

Что тут не так? почему индекс не используется? А то таблица geo_worldcities большая и без индексов все жутко тормозит. (большая - это примерно 200 МБ и несколько миллионов записей)
 

Wicked

Новичок
потому что индексы не предназначены для условий ИЛИ, включающих разные поля.
 

phprus

Moderator
Команда форума
Wicked
То есть если в таблице есть индексы по полям cityname и accentcityname, то при выборке по условию OR между этими полями эти индексы вообще не будут использоваться? Я правильно понял?

-~{}~ 04.07.06 17:46:

Если да то можно ли как либо ускорить этот запрос?
 

Wicked

Новичок
phprus
правильно.

Кроме UNION'а еще может помочь вынесение этих двух полей в отдельную таблицу, где они будут располагаться в один столбец. Либо использование fulltext index'а, но он накладывает доп. ограничения.
 

phprus

Moderator
Команда форума
Wicked
Как то странно это. Почему бы MySQL не выбирать сначала записи удовлетворяющие первому условию, а потом второму (с использованием соответствующих индексов) после чего объединять эти выборки и выдавать окончательный результат
.
вынесение этих двух полей в отдельную таблицу
Это мне не подходит, так как такая таблица будет занимать много места.

Наверно придется попробовать воспользоваться UNION.
 

phprus

Moderator
Команда форума
А если условия калькулируемые? .
Об этом я не подумал. :)

Я сделал с использованием UNION и теперь все работает так как надо и с нужной скоростью.

Спасиб всем кто отвечал в этой теме за помощь в решении моей проблемы.
 
Сверху