Я создаю приложение для генерации авиаперевозок. Местоположение пользователя запрашивается из базы данных, и они вводят минимальное расстояние, которое они хотят пролететь, и максимальное расстояние, которое они хотят пролететь. Мне нужно составить список аэропортов, которые находятся между этими диапазонами, от аэропорта их происхождения. У меня есть функция для расчета расстояния, но я могу использовать ее, только если сначала извлекаю все данные аэропорта из базы данных, что очень дорого. Есть ли способ сделать это в коде MySQL.
Спасибо,
Дейв
Великое расстояние круга доступно в http://mysql.rjweb.org/doc.php/latlng как хранимая функция.
Да, я верю, что вы могли бы сделать это в БД. Я использую аналогичную идею и запускаю код в хранимой процедуре — передавая параметры для lat / lng / radius. Код ниже должен дать представление о том, как вы могли бы реализовать это для ваших собственных нужд, я думаю.
begin
declare strsql varchar(1000);
declare dbrecords integer default 0;
declare maxlimit integer default 0;
declare lat double default 0;
declare lng double default 0;
declare radius float default 0;
declare earth_radius integer default 0;
declare lon1 float;
declare lat1 float;
declare lon2 float;
declare lat2 float;
set @lat=param_lat;
set @lng=param_lng;
set @radius=cast(param_radius as unsigned);
set @earth_radius=3956;
set @lon1 = @lng - @radius/ceil( cos( radians( @lat ) ) * 69 );
set @lon2 = @lng + @radius/ceil( cos( radians( @lat ) ) * 69 );
set @lat1 = @lat - ( @radius/69 );
set @lat2 = @lat + ( @radius/69 );
set @maxlimit=cast(param_limit as unsigned);
set @strsql=concat("select distinct
m.`lat`,
m.`lng`,
m.`alt`,
m.`region`,
m.`unitaryautharea`,
c.`council_name`,
c.`normalised_title`,
c.`council_lat`,
c.`council_lng`,
c.`cipfa_code`,
c.`snac_id`,
c.`wdtk_id`,
c.`wdtk_name`,
c.`egr_id`,
c.`os_id`,
c.`open_data_licence`
w.`country_name`,
/* This is the bit that does the main calculations and probably where you want to concentrate - the fields obviously will not relate to your db */
truncate( @earth_radius * 2 * asin(sqrt( power( sin( (@lat - m.`lat`) * pi()/180 / 2), 2) +cos(@lat * pi()/180) * cos(m.`lat` * pi()/180) *power(sin((@lng - m.`lng`) * pi()/180 / 2), 2) ) ),3) as 'distance'from `metsitelist` m
left outer join `ukcity_councils` c on c.`normalised_title`=m.`unitaryautharea`
left outer join `ukcity_districts` d on d.`council_id`=c.`council_id`
left outer join `ukcouncil_type` t on t.`id`=c.`council_authority_type_id`
left outer join `ukcounties` ct on ct.`county_id`=c.`county_id`
left outer join `worldcountries` w on w.`country_id`=c.`country_id`
left outer join `metregions` r on r.`region`=m.`region`
/* Here you find records within the range you want */
where (
( m.`lat` between @lat1 and @lat2 )
and
( m.`lng` between @lon1 and @lon2 )
)/* ensure records are closer than max radius */having `distance` <= @radius
order by `distance`
limit 0", @maxlimit ,";");
prepare stmt from @strsql;
execute stmt;
deallocate prepare stmt;
end
Надеюсь, что вы можете использовать логику здесь
Хм, вы можете уменьшить размер запроса, но не вычислить всю задачу (легко или не так легко, как на стороне PHP) в базе данных. Эта оптимизация не связана с PHP, связана только с MySQL (SQL), и цель состоит в том, чтобы значительно сократить количество элементов для вычисления на стороне PHP.
Если у вас есть максимальное расстояние, вы можете запросить информацию обо всех аэропортах в этом диапазоне и использовать только их для расчета наилучшего маршрута.
SELECT * FROM (
SELECT id, name, x, y,
SQRT(POW(ABS(xpos - x), 2) + POW(ABS(ypos - y), 2)) distance
FROM table_name
) temp_table WHERE distance < max_distance
Это не решит проблему, но поможет сократить работу на стороне PHP.
Надеюсь, поможет.