Сложно сказать, с чего начать, но, насколько я могу судить, на основании вопроса до моего редактирования
- У вас был большой SQL-запрос в виде строкового литерала в php.
- Это было полностью не отформатировано.
- Он был написан сложным и повторяющимся образом.
Все это делает ошибки вероятными, трудными для выявления и исправлениями.
- Поместить sql в свой собственный файл может быть хорошей идеей. Другие варианты включают использование инструментов построителя запросов или перемещение сложности запроса в вашу базу данных в виде представления БД.
- Всегда форматируйте весь код для удобочитаемости и удобства обслуживания. Это так, чтобы люди могли помочь вам с этим.
x <> NULL
- это NULL
, что неверно, поэтому вам не нужно отдельно проверять NULL.
- Вы можете , вероятно, использовать
COUNT(*)
вместо COUNT(table.id)
, что более читабельно, но если table.id
не означает, что это выглядит, значит, возможно, это неправильно.
- Двойные
SELECT
- это большой красный флаг, как с точки зрения читабельности, так и с точки зрения производительности. Вы можете избавиться от них, полагаясь на тот факт, что когда вы не используете COUNT(*)
, COUNT не считается NULL
с.
- Рассмотрим всегда с использованием псевдонимов для таблиц, но если вы используете одну и ту же таблицу несколько раз в запросе, то вы должны безусловно псевдоним каждый раз.
- Всегда используйте явные типы JOIN и помните о различиях между ними.
SELECT pe_projects.*
, pe_project_status.status_t
, pe_project_status.orderby
, pe_pocs.first_name AS 'poc_first_name'
, pe_pocs.last_name AS 'poc_last_name'
, pe_clients.id AS 'client_id'
, pe_clients.short_name
, pe_employees.first_name AS 'pe_first_name'
, pe_employees.last_name AS 'pe_last_name'
, (SELECT COUNT(*)
FROM pe_instrument_tracking pit
WHERE pit.project_id = pe_projects.id
) AS total_inst
, (SELECT COUNT(
CASE WHEN pit_o.ordered <> '0000-00-00' THEN pit_o.id END
) / COUNT(*) * 100
FROM pe_instrument_tracking pit_o
WHERE pit_o.project_id = pe_projects.id
) AS ordered_per
, (SELECT COUNT(
CASE WHEN pit_r.received <> '0000-00-00' THEN pit_r.id END
) / COUNT(*) * 100
FROM pe_instrument_tracking pit_r
WHERE pit_r.project_id = pe_projects.id
) AS received_per
, (SELECT COUNT(
CASE WHEN pit_i.installed <> '0000-00-00' THEN pit_i.id END
) / COUNT(*) * 100
FROM pe_instrument_tracking pit_i
WHERE pit_i.project_id = pe_projects.id
) AS installed_per
, (SELECT COUNT(
CASE WHEN pit_t.tested <> '0000-00-00' THEN pit_t.id END
) / COUNT(*) * 100
FROM pe_instrument_tracking pit_t
WHERE pit_t.project_id = pe_projects.id
) AS tested_per
FROM pe_projects
LEFT JOIN pe_project_status ON pe_projects.status_id = pe_project_status.id
LEFT JOIN pe_pocs ON pe_projects.client_contact_id = pe_pocs.id
LEFT JOIN pe_clients ON pe_projects.client_id = pe_clients.id
LEFT JOIN pe_employees ON pe_projects.employee_id = pe_employees.id
WHERE NOT pe_projects.deleted
AND pe_projects.department = '1'
Выше все еще не очень хорошо. В частности, существует пять подзапросов к одной таблице pe_instrument_tracking
. Предполагая, что вы используете достаточно актуальную версию MySQL, вы можете исправить это с помощью подзапроса типа «производная таблица»:
SELECT pe_projects.*
, pe_project_status.status_t
, pe_project_status.orderby
, pe_pocs.first_name AS 'poc_first_name'
, pe_pocs.last_name AS 'poc_last_name'
, pe_clients.id AS 'client_id'
, pe_clients.short_name
, pe_employees.first_name AS 'pe_first_name'
, pe_employees.last_name AS 'pe_last_name'
, pit.total AS total_inst
, pit.ordered AS ordered_per
, pit.received AS received_per
, pit.installed AS installed_per
, pit.tested AS tested_per
FROM pe_projects
LEFT JOIN pe_project_status ON pe_projects.status_id = pe_project_status.id
LEFT JOIN pe_pocs ON pe_projects.client_contact_id = pe_pocs.id
LEFT JOIN pe_clients ON pe_projects.client_id = pe_clients.id
LEFT JOIN pe_employees ON pe_projects.employee_id = pe_employees.id
LEFT JOIN (SELECT COUNT(*) AS total
, 100
* COUNT(CASE WHEN pe_instrument_tracking.ordered <> '0000-00-00' THEN 1 END)
/ COUNT(*) AS ordered
, 100
* COUNT(CASE WHEN pe_instrument_tracking.received <> '0000-00-00' THEN 1 END)
/ COUNT(*) AS received
, 100
* COUNT(CASE WHEN pe_instrument_tracking.installed <> '0000-00-00' THEN 1 END)
/ COUNT(*) AS installed
, 100
* COUNT(CASE WHEN pe_instrument_tracking.tested <> '0000-00-00' THEN 1 END)
/ COUNT(*) AS tested
FROM pe_instrument_tracking ON pe_instrument_tracking.project_id = pe_projects.id
) AS pit
WHERE NOT pe_projects.deleted
AND pe_projects.department = '1'
Обратите внимание, что ни один из них не обращается к предупреждающему сообщению, о котором вы действительно спрашиваете.
Но теперь, когда у вас более короткий и понятный запрос, можно надеяться, что он начнет рассуждать о том, какие ключи и индексы ему понадобятся для эффективной работы.