У меня есть база данных, которая уже используется, и я должен улучшить производительность системы, которая использует эту базу данных.
Есть 2 основных запроса, выполняющихся около 1000 раз в цикле, и эти запросы имеют внутренние объединения с 3 другими таблицами каждый. Это, в свою очередь, делает систему очень медленной.
На самом деле я пытался удалить запрос из цикла, извлечь все данные только один раз и обработать его в PHP. Но это создает большую нагрузку на память (RAM), и система зависает, если 2 или более клиентов пытаются использовать систему.
В таблицах содержится много данных даже после удаления просроченных данных.
Я приложил запрос ниже.
Кто-нибудь может мне помочь с этим вопросом?
select * from inventory
where (region_id = 38 or region_id = -1)
and (tour_opp_id = 410 or tour_opp_id = -1)
and room_plan_id = 141 and meal_plan_id = 1 and bed_type_id = 1 and hotel_id = 1059
and FIND_IN_SET(supplier_code, 'QOA,QTE,QM,TEST,TEST1,MQE1,MQE3,PERR,QKT')
and ( ('2014-11-14' between from_date and to_date) )
order by hotel_id desc ,supplier_code desc, region_id desc,tour_opp_id desc,inventory.inventory_id descSELECT * ,pinfo.fri as pi_day_fri,pinfoadd.fri as pa_day_fri,pinfochld.fri as pc_day_fri
FROM `profit_markup`
inner join profit_markup_info as pinfo on pinfo.profit_id = profit_markup.profit_markup_id
inner join profit_markup_add_info as pinfoadd on pinfoadd.profit_id = profit_markup.profit_markup_id
inner join profit_markup_child_info as pinfochld on pinfochld.profit_id = profit_markup.profit_markup_id
where profit_markup.hotel_id = 1059 and (`booking_channel` = 1 or `booking_channel` = 2)
and (`rate_region` = -1 or `rate_region` = 128)
and ( ( period_from <= '2014-11-14' and period_to >= '2014-11-14' ) )
ORDER BY profit_markup.hotel_id DESC,supplier_code desc, rate_region desc,operators_list desc, profit_markup_id DESC
Так как мы не видели ваши SHOW CREATE TABLES;
а также EXPLAIN EXTENDED
планировать трудно дать 1 ответ
Но, вообще говоря, в отношении вашего запроса «Кстати, я переписал ниже»
SELECT
hotel_id, supplier_code, region_id, tour_opp_id, inventory_id
FROM
inventory
WHERE
region_id IN (38, -1)
AND tour_opp_id IN (410, -1)
AND room_plan_id IN (141, 1)
AND bed_type_id IN (1, 1059)
AND supplier_code IN ('QOA', 'QTE', 'QM', 'TEST', 'TEST1', 'MQE1', 'MQE3', 'PERR', 'QKT')
AND ('2014-11-14' BETWEEN from_date AND to_date )
ORDER BY
hotel_id DESC, supplier_code DESC, region_id DESC, tour_opp_id DESC, inventory_id DESC
Не использовать *
чтобы получить все столбцы. Вы должны перечислить столбец, который вам действительно нужен. С помощью *
это просто ленивый способ написания запроса. ограничение столбцов будет ограничивать размер данных, который выбирается.
Как часто записи в инвентаре обновляются / вставляются / удаляются? Если не слишком часто, то вы можете использовать рассмотреть возможность использования SQL_CACHE
, Однако кэширование запроса вызовет у вас проблемы, если вы его используете, и таблица инвентаризации обновляется очень часто. Кроме того, чтобы использовать кеш запросов, необходимо проверить значение query_cache_type
на вашем сервере. SHOW GLOBAL VARIABLES LIKE 'query_cache_type';
, Если установлено значение «0», то функция кэширования отключена и SQL_CACHE
будут игнорироваться Если установлено значение 1, то сервер будет кэшировать все запросы, если вы не скажете, что это не слишком NO_SQL_CACHE
, Если для параметра задано значение 2, MySQL будет кэшировать запрос только в том случае, если используется предложение SQL_CACHE. вот документация о query_cache_type
Если у вас есть указатель на следующие столбцы в этом порядке, это поможет вам (hotel_id, supplier_code, region_id, tour_opp_id, inventory_id)
ALTER TABLE inventory
ADD INDEX (hotel_id, supplier_code, region_id, tour_opp_id, inventory_id);
Если возможно увеличить sort_buffer_size
на вашем сервере, поскольку, скорее всего, вы выдаете здесь вопрос о том, что вы делаете слишком много сортировки.
Что касается второго запроса «Кстати, я переписал ниже»
SELECT
*, pinfo.fri as pi_day_fri,
pinfoadd.fri as pa_day_fri,
pinfochld.fri as pc_day_fri
FROM
profit_markup
INNER JOIN
profit_markup_info AS pinfo ON pinfo.profit_id = profit_markup.profit_markup_id
INNER JOIN
profit_markup_add_info AS pinfoadd ON pinfoadd.profit_id = profit_markup.profit_markup_id
INNER JOIN
profit_markup_child_info AS pinfochld ON pinfochld.profit_id = profit_markup.profit_markup_id
WHERE
profit_markup.hotel_id = 1059
AND booking_channel IN (1, 2)
AND rate_region IN (-1, 128)
AND period_from <= '2014-11-14'
AND period_to >= '2014-11-14'
ORDER BY
profit_markup.hotel_id DESC, supplier_code DESC, rate_region DESC,
operators_list DESC, profit_markup_id DESC
Снова исключить использование *
из вашего запроса
Убедитесь, что следующие столбцы имеют одинаковый тип / сопоставление и одинаковый размер. pinfo.profit_id, profit_markup.profit_markup_id, pinfoadd.profit_id, pinfochld.profit_id
и у каждого должен быть индекс на каждой таблице. Если столбцы имеют разные типы, MySQL будет каждый раз преобразовывать данные, чтобы объединить записи. Даже если у вас есть индекс, он будет медленнее. Кроме того, если эти столбцы имеют тип символов (например, VARCHAR ()), убедитесь, что они относятся к CHAR()
с сопоставлением latin1_general_ci
так как это будет быстрее для поиска ID, но если вы используете INT (), даже лучше.
Используйте 3-й и 4-й приемы, которые я перечислил для предыдущего запроса
Попробуйте использовать STRAIGHT_JOIN: «Вы должны знать, что вы здесь делаете, иначе это вас укусит!» Вот хорошая ветка об этом Когда использовать STRAIGHT_JOIN с MySQL
Надеюсь, это поможет.
Для первого запроса я не уверен, что вы можете многое сделать (при условии, что вы уже проиндексировали поля, по которым вы упорядочиваете), кроме замены * на имена столбцов (не ожидайте, что это резко повысит производительность).
Для второго запроса, прежде чем пройти через цикл и ввести аргументы выбора, вы можете создать представление со всеми объединенными и упорядоченными таблицами, а затем создать подготовленный оператор для выбора из представления и связать аргументы в цикле.
Кроме того, если ваш php-сервер и сервер базы данных находятся в двух разных местах, лучше, если вы сделали выбор с помощью хранимой процедуры в базе данных.
(Если ничего не получается, то лучше всего использовать memcache … Хотя лично я никогда не делал этого)
Здесь вы увеличиваете производительность запросов, а не производительность базы данных.
Для обоих запросов первый проверочный индекс доступен для столбцов предложения WHERE и ON (Join), если индекс отсутствует, необходимо добавить индекс для повышения производительности запроса.
Проверьте объяснение плоскости перед созданием индекса.
По возможности покажите мне плоскость объяснения обоих запросов, которая поможет нам.