В следующем сокращенном запросе выбираются все строки (entrys
) на заданном расстоянии (рассчитывается пользователем e.altloc = 0: location
или e.altloc = 1: altlocation
).
У меня есть индексы для e.uid, al.eid, e.country, e.tmstmp, а id
являются первичными ключами.
Задача в соответствии с объяснением - все строки нужны для обработки запроса, а не 2 строки, которые мне нравятся с пределом 2.
Я прочитал этот вопрос, но я не могу установить ограничение перед использованием присоединиться, потому что мне нужно объединить таблицы местоположений, прежде чем я смогу сделать limit 2
, иначе возврат будет неправильным.
https://dba.stackexchange.com/questions/52079/does-using-limit-improve-the-performance-and-is-it-noticeable
Запрос:
SELECT
e.id, e.uid, e.title, e.description, l.place, l.placenonce, al.altplace, al.altplacenonce,
IF(e.altloc=0,
6371 * acos( cos( radians(:lat) ) * cos( radians( AES_DECRYPT(lat, UNHEX('###'), latnonce) ) ) * cos( radians( AES_DECRYPT(lng, UNHEX('###'), lngnonce) ) - radians(:lng) ) + sin( radians(:lat) ) * sin(radians(AES_DECRYPT(lat, UNHEX('###'), latnonce))) ) ,
6371 * acos( cos( radians(:lat) ) * cos( radians( AES_DECRYPT(altlat, UNHEX('###'), altlatnonce) ) ) * cos( radians( AES_DECRYPT(altlng, UNHEX('###'), altlngnonce) ) - radians(:lng) ) + sin( radians(:lat) ) * sin(radians(AES_DECRYPT(altlat, UNHEX('###'), altlatnonce))) )
) AS distance
FROM
entrys e
INNER JOIN
location l
ON l.id = e.uid
LEFT JOIN
altlocation al
ON al.eid = e.id
WHERE
IF(:border = 0, e.country = :countryid, e.country != 0 )
HAVING
distance <= 50
ORDER BY
e.tmstmp
DESC
LIMIT 2
Второй пример с фиксированным местоположением:
SELECT
s.id, s.image, s.description, s.title,
(
6371 * acos( cos( radians(:lat) ) * cos( radians( AES_DECRYPT(l.lat, :key, l.latnonce) ) ) * cos( radians( AES_DECRYPT(l.lng, :key, l.lngnonce) ) - radians(:lng) ) + sin( radians(:lat) ) * sin(radians(AES_DECRYPT(l.lat, :key, l.latnonce))) )
) AS distance
FROM
sponsors s
INNER JOIN
location l
ON l.id = s.id
WHERE
s.comp = 1 OR s.comp = 3 AND s.active = 1
HAVING
distance <= 50
ORDER BY
s.rotate
ASC
LIMIT 2
Как улучшить эти запросы на основе местоположения, если в моей базе данных есть миллион строк? Мне нужно вывести только 2 строки каждого запроса.
Создать таблицу для первого примера:
CREATE TABLE `entrys` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uid` int(5) NOT NULL,
`tmstmp` bigint(11) NOT NULL,
`approx_lat` mediumint(9) NOT NULL,
`approx_lng` mediumint(9) NOT NULL,
`altloc` tinyint(4) NOT NULL,
`title` varchar(70) COLLATE latin1_general_ci NOT NULL,
`description` text COLLATE latin1_general_ci NOT NULL,
`country` tinyint(4) NOT NULL,
PRIMARY KEY (`id`),
KEY `uid` (`uid`),
KEY `tmstmp` (`tmstmp`),
KEY `country` (`country`),
) ENGINE=MyISAM CHARSET=latin1 COLLATE=latin1_general_ci
CREATE TABLE `location` (
`id` int(5) NOT NULL,
`lat` varbinary(50) NOT NULL,
`latnonce` varbinary(25) NOT NULL,
`lng` varbinary(50) NOT NULL,
`lngnonce` varbinary(25) NOT NULL,
`place` tinyblob NOT NULL,
`placenonce` tinyblob NOT NULL,
UNIQUE KEY `id` (`id`),
KEY `lat` (`lat`),
KEY `lng` (`lng`)
)
CREATE TABLE `altlocation` (
`id` int(5) NOT NULL,
`eid` int(5) NOT NULL,
`altlat` varbinary(50) NOT NULL,
`altlatnonce` varbinary(25) NOT NULL,
`altlng` varbinary(50) NOT NULL,
`altlngnonce` varbinary(25) NOT NULL,
`altplace` tinyblob NOT NULL,
`altplacenonce` tinyblob NOT NULL,
UNIQUE KEY `eid` (`eid`),
KEY `altlat` (`altlat`),
KEY `altlng` (`altlng`)
)
sidenote: движок для записей, вероятно, должен быть innodb, прочитав ~ 70%. Таблицы местоположений работают с innodb.
РЕДАКТИРОВАТЬ вопрос к Виллему Рензема для его ответа:
Будет ли так эффективнее?
SELECT
e.id, e.uid, e.title, e.description, l.place, l.placenonce, al.altplace, al.altplacenonce,
IF(e.altloc=0,
6371 * acos( cos( radians(:lat) ) * cos( radians( AES_DECRYPT(lat, UNHEX('###'), latnonce) ) ) * cos( radians( AES_DECRYPT(lng, UNHEX('###'), lngnonce) ) - radians(:lng) ) + sin( radians(:lat) ) * sin(radians(AES_DECRYPT(lat, UNHEX('###'), latnonce))) ) ,
6371 * acos( cos( radians(:lat) ) * cos( radians( AES_DECRYPT(altlat, UNHEX('###'), altlatnonce) ) ) * cos( radians( AES_DECRYPT(altlng, UNHEX('###'), altlngnonce) ) - radians(:lng) ) + sin( radians(:lat) ) * sin(radians(AES_DECRYPT(altlat, UNHEX('###'), altlatnonce))) )
) AS distance
FROM
(
SELECT id, uid, title, description
FROM
entrys
WHERE
approx_lat > :min_lat
AND approx_lat < :max_lat
AND approx_lng > :min_lng
AND approx_lng < :min_lng
ORDER BY
e.tmstmp
DESC
LIMIT 2
) AS e
INNER JOIN
location l
ON l.id = uid
LEFT JOIN
altlocation al
ON al.eid = e.id
HAVING
distance <= 50
Если бы я добавил прибл. И ок. В таблицу входов
Подсказка будет перемещаться приблизительно в плоскость ввода и указывать приблизительную ширину и приблизительную величину, чтобы я мог вставить только ИЛИ расположение или только местоположение, чтобы я мог избавиться от IF
внутри запроса.
HAVING distance <= 50
все еще необходимо?