Я изучаю это навсегда, и я начинаю думать, что я не могу сделать это более эффективным, но я хотел спросить, есть ли у кого-нибудь советы.Есть ли способ оптимизировать сложный математический запрос в MySQL?
Я выполняю запрос по миллионам записей, чтобы найти все координаты x, y, z (это звезды) вдоль линейного столбца от системы a до системы b с заданным радиусом. Я работаю через PHP с большим количеством других работ, выполняемых в результирующем наборе. Я получаю результаты от скрипта примерно за 16 секунд. Задержка запроса составляет около 7 из этих 16 секунд.
Основная логика запроса:
SELECT name, coordinates, and distance from end point
FROM stars
WHERE all stars are in a column of given radius between start and end points
ORDER BY distance from end point DESC
где положение требует двух отдельных вычислений, они это:
Где расчета 1:
Calculate if the stars are within the space of the column using constants and x,y,z
Где расчет 2:
Limit the column radius to a given figure.
(This where clause also performs similar calculations with the same constants and x,y,z.)
Математические формулы в тех случаях, когда предложения не могут быть изменены, являются формулой, необходимой для вычисления столбцов в трехмерном пространстве.
Порядок в конце запроса абсолютно необходим, потому что набор результатов слишком велик для хранения моего сценария в памяти. Я должен работать с ним в правильном порядке в скрипте.
Запрос легче читать, как определено до подстановки переменных:
SELECT
name,
x,
y,
z,
SQRT(
pow(`x`-" . $bx . ",2)+
pow(`y`-" . $by . ",2)+
pow(`z`-" . $bz . ",2)
) d
FROM
stars
WHERE
(((`x`*$cx+`y`*$cy+`z`*$cz)-($constant_1))/($constant_2)) between 0 and 1
AND
SQRT(((($ax + ((((`x`*$cx+`y`*$cy+`z`*$cz)-($constant_1))/($constant_2)) * $cx))-`x`)*(($ax + ((((`x`*$cx+`y`*$cy+`z`*$cz)-($constant_1))/($constant_2)) * $cx))-`x`))+((($ay + ((((`x`*$cx+`y`*$cy+`z`*$cz)-($constant_1))/($constant_2)) * $cy))-`y`)*(($ay + ((((`x`*$cx+`y`*$cy+`z`*$cz)-($constant_1))/($constant_2)) * $cy))-`y`))+((($az + ((((`x`*$cx+`y`*$cy+`z`*$cz)-($constant_1))/($constant_2)) * $cz))-`z`)*(($az + ((((`x`*$cx+`y`*$cy+`z`*$cz)-($constant_1))/($constant_2)) * $cz))-`z`)))
<=$radius
ORDER BY
SQRT(
pow(`x`-" . $bx . ",2)+
pow(`y`-" . $by . ",2)+
pow(`z`-" . $bz . ",2)
) DESC
Окончательный запуск запроса в базе данных выглядит следующим образом: (Для простоты я использую данные примеры, где много из константы 0.)
SELECT
name,
x,
y,
z,
SQRT(pow(`x`-25.21875,2)+ pow(`y`--20.90625,2)+ pow(`z`-25899.96875,2)) d
FROM
stars
WHERE
(((`x`*25.21875+`y`*-20.90625+`z`*25899.96875)-(0))/(670809454.308))
between 0 and 1
AND
SQRT((((0 + ((((`x`*25.21875+`y`*-20.90625+`z`*25899.96875)-(0))/(670809454.308)) * 25.21875))-`x`)*((0 + ((((`x`*25.21875+`y`*-20.90625+`z`*25899.96875)-(0))/(670809454.308)) * 25.21875))-`x`))+(((0 + ((((`x`*25.21875+`y`*-20.90625+`z`*25899.96875)-(0))/(670809454.308)) * -20.90625))-`y`)*((0 + ((((`x`*25.21875+`y`*-20.90625+`z`*25899.96875)-(0))/(670809454.308)) * -20.90625))-`y`))+(((0 + ((((`x`*25.21875+`y`*-20.90625+`z`*25899.96875)-(0))/(670809454.308)) * 25899.96875))-`z`)*((0 + ((((`x`*25.21875+`y`*-20.90625+`z`*25899.96875)-(0))/(670809454.308)) * 25899.96875))-`z`)))
<=600
ORDER BY
SQRT(pow(`x`-25.21875,2)+ pow(`y`--20.90625,2)+ pow(`z`-25899.96875,2)) DESC
Мое определение таблицы выглядит следующим образом:
CREATE TABLE IF NOT EXISTS `stars` (
`localkey` bigint(20) NOT NULL AUTO_INCREMENT,
`id` bigint(20) NOT NULL,
`x` double NOT NULL,
`y` double NOT NULL,
`z` double NOT NULL,
`name` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`localkey`),
UNIQUE KEY `id` (`id`),
KEY `x` (`x`),
KEY `y` (`y`),
KEY `z` (`z`),
KEY `xyz` (`x`,`y`,`z`),
KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
объяснить результатов запроса не указывает на использование индекса и дополнительной сложности:
extra: Using where; Using filesort;
То, что я пытался до сих пор:
- Настройка различных типов данных для оптимизации использования памяти и индексации (Даже если моя математика делает маловероятными индексы когда-либо использоваться)
- Использование цикла PHP и нескольких меньших запросов вместо этого одного огромного (потребовалось больше времени с несколькими запросами.)
- Копирование в таблицу памяти перед запуском запроса (Таблица слишком rge для установки в память)
- Копирование только части таблицы (localkey, x, y, z) в память. (Это подойдет, но осталось так мало от max_heap_size для других процессов, что этого не стоило.)
Есть ли другие варианты, которые мне не хватает?
Спасибо!
Из любопытства, что начинается данные посаженные это? Это какой-то искусственный набор данных, с которым вы работаете, или это доступный набор данных с открытым исходным кодом. Было бы здорово, если бы вы могли указать мне на это. благодаря! – Shaunak
@Shaunak Извините за задержку в ответе. Я отвечал по телефону на другие комментарии и не мог легко ответить. Есть несколько ресурсов для звездных наборов данных: http://ned.ipac.caltech.edu/ http://simbad.u-strasbg.fr/simbad/ Но я на самом деле делаю это как инструмент, чтобы помочь моему другому хобби, который играет в космические симы. Набор данных, который я использую, основан на Simbad, я полагаю, но разработчики игр изменили некоторые имена для сюжетных целей. Мой набор данных отсюда: https://www.edsm.net/nightly-dumps Редактирование: Случайно отправлено без URLS – Gerdofal