Прежде всего, я рассмотрел несколько других вопросов об оптимизации SQL-запросов, но мне все еще непонятно для моей ситуации, что вызывает мою проблему. Я также прочитал несколько статей по этой теме и попытался реализовать несколько возможных решений, как я опишу ниже, но пока что ничего не помогло и даже не внесло заметный вклад в проблему.
Приложение представляет собой систему отслеживания питания - пользователи вводят продукты, которые они едят, и на основе импортированной базы данных USDA приложение разбивает продукты на отдельные питательные вещества и дает пользователю разбивку количеств питательных веществ по (на данный момент) ежедневно.
здесь
PDF сокращенной схемы базы данных
и здесь это как (возможно, плохое качество) JPG. Я сделал это в открытом офисе - если есть предложения по лучшим способам визуализации базы данных, я также открыт для предложений в этой области! Синие столы прямо из USDA, а зеленые и черные - те, которые я сделал. Я опустил много данных, чтобы не загромождать ненужные вещи.
Вот запрос, который я пытаюсь выполнить, который занимает очень много времени:
SELECT listing.date_time,listing.nutrdesc,data.total_nutr_mass,listing.units
FROM
(SELECT nutrdesc, nutr_no, date_time, units
FROM meals, nutr_def
WHERE meals.users_userid = '2'
AND date_time BETWEEN '2009-8-12' AND '2009-9-12'
AND (nutr_no <100000
OR nutr_no IN
(SELECT nutr_def_nutr_no
FROM nutr_rights
WHERE nutr_rights.users_userid = '2'))
) as listing
LEFT JOIN
(SELECT nutrdesc, date_time, nut_data.nutr_no, sum(ingred_gram_mass*entry_qty_num*nutr_val/100) AS total_nutr_mass
FROM nut_data, recipe_ingredients, food_entries, meals, nutr_def
WHERE nut_data.nutr_no = nutr_def.nutr_no
AND ndb_no = ingred_ndb_no
AND foods_food_id = entry_ident
AND meals_meal_id = meal_id
AND users_userid = '2'
AND date_time BETWEEN '2009-8-12' AND '2009-9-12'
GROUP BY date_time,nut_data.nutr_no ) as data
ON data.date_time = listing.date_time
AND listing.nutr_no = data.nutr_no
ORDER BY listing.date_time,listing.nutrdesc,listing.units
Так что я знаю, что это довольно сложно - первый выбор получает список всех питательных веществ, которые пользователь потребил в указанном диапазоне дат, а второй заполняет все количества.
Когда я реализую их отдельно, первый запрос действительно быстрый, но второй - медленный, а очень медленный, когда диапазоны дат становятся большими. Объединение делает все это смехотворно медленным. Я знаю, что «главная» проблема - это объединение этих двух производных таблиц, и я могу избавиться от этого и выполнить соединение вручную в основном в php гораздо быстрее, но я не уверен, что это вся история.
Например: для данных за 1 месяц запрос занимает около 8 секунд, что медленно, но не совсем ужасно. Отдельно каждый запрос занимает ~ 0,01 и ~ 2 секунды соответственно. 2 секунды все еще кажутся мне высокими.
Если я пытаюсь получить данные за год, выполнение всего запроса занимает несколько (> 10) минут, что проблематично - иногда соединение клиент-сервер прерывается, и в любом случае мы не хотим Я не хочу сидеть там с вращающейся иконкой «пожалуйста, подождите». В основном, я чувствую, что есть проблема, потому что для получения 12-кратной дополнительной информации требуется больше, чем в 12 раз, а для правильной работы требуется менее 12 раз.
Вот «объяснение» для каждого из медленных запросов: (все и только вторая половина).
Всего:
+----+--------------------+--------------------+----------------+-------------------------------+------------------+---------+-----------------------------------------------------------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+--------------------+----------------+-------------------------------+------------------+---------+-----------------------------------------------------------------------+------+----------------------------------------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 5053 | Using temporary; Using filesort |
| 1 | PRIMARY | <derived4> | ALL | NULL | NULL | NULL | NULL | 4341 | |
| 4 | DERIVED | meals | range | PRIMARY,day_ind | day_ind | 9 | NULL | 30 | Using where; Using temporary; Using filesort |
| 4 | DERIVED | food_entries | ref | meals_meal_id | meals_meal_id | 5 | nutrition.meals.meal_id | 15 | Using where |
| 4 | DERIVED | recipe_ingredients | ref | foods_food_id,ingred_ndb_no | foods_food_id | 4 | nutrition.food_entries.entry_ident | 2 | |
| 4 | DERIVED | nutr_def | ALL | PRIMARY | NULL | NULL | NULL | 174 | |
| 4 | DERIVED | nut_data | ref | PRIMARY | PRIMARY | 36 | nutrition.nutr_def.nutr_no,nutrition.recipe_ingredients.ingred_ndb_no | 1 | |
| 2 | DERIVED | meals | range | day_ind | day_ind | 9 | NULL | 30 | Using where |
| 2 | DERIVED | nutr_def | ALL | PRIMARY | NULL | NULL | NULL | 174 | Using where |
| 3 | DEPENDENT SUBQUERY | nutr_rights | index_subquery | users_userid,nutr_def_nutr_no | nutr_def_nutr_no | 19 | func | 1 | Using index; Using where |
+----+--------------------+--------------------+----------------+-------------------------------+------------------+---------+-----------------------------------------------------------------------+------+----------------------------------------------+
10 rows in set (2.82 sec)
Второй кусок (данные):
+----+-------------+--------------------+-------+-----------------------------+---------------+---------+-----------------------------------------------------------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------------+-------+-----------------------------+---------------+---------+-----------------------------------------------------------------------+------+----------------------------------------------+
| 1 | SIMPLE | meals | range | PRIMARY,day_ind | day_ind | 9 | NULL | 30 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | food_entries | ref | meals_meal_id | meals_meal_id | 5 | nutrition.meals.meal_id | 15 | Using where |
| 1 | SIMPLE | recipe_ingredients | ref | foods_food_id,ingred_ndb_no | foods_food_id | 4 | nutrition.food_entries.entry_ident | 2 | |
| 1 | SIMPLE | nutr_def | ALL | PRIMARY | NULL | NULL | NULL | 174 | |
| 1 | SIMPLE | nut_data | ref | PRIMARY | PRIMARY | 36 | nutrition.nutr_def.nutr_no,nutrition.recipe_ingredients.ingred_ndb_no | 1 | |
+----+-------------+--------------------+-------+-----------------------------+---------------+---------+-----------------------------------------------------------------------+------+----------------------------------------------+
5 rows in set (0.00 sec)
Я «проанализировал» все таблицы, включенные в запрос, и добавил индекс в поле даты и времени, которое объединяет записи о блюдах и продуктах. Я назвал это «day_ind». Я надеялся, что это ускорит ситуацию, но, похоже, это ничего не изменит. Я также попытался удалить функцию 'sum', так как понимаю, что наличие функции в запросе часто будет означать полное сканирование таблицы, которое, очевидно, намного медленнее. К сожалению, удаление «суммы», похоже, тоже не имело значения (ну, примерно 3-5% или около того, но не величина порядка, который я ищу).
Буду рад любым предложениям и буду рад предоставить любую дополнительную информацию, необходимую для диагностики и улучшения этой проблемы. Заранее спасибо!