#php #mysql
Вопрос:
этот запрос
SELECT * FROM kp_landing_page lp WHERE lp.parent = '7' AND ( SELECT COUNT(*) FROM kp_landing_page_product lpp WHERE lpp.landing_page_id = lp.landing_page_id AND lpp.productid = '6176' ) != 0
для завершения требуется около 1 минуты, я попытался переписать его следующим образом
SELECT * FROM kp_landing_page lp INNER JOIN (SELECT COUNT(*) FROM kp_landing_page_product lpp WHERE lpp.landing_page_id = lp.landing_page_id AND lpp.productid = '6176') != 0 WHERE lp.parent = '7'
Хотя это намного быстрее (3-4 секунды), он не получает необходимых данных, которые мне нужны, даже если все таблицы остаются прежними, и выполнение этого запроса внутри phpmyadmin дает мне те же данные, что и старый. это просто выдает мне следующую ошибку
The current selection does not contain a unique column. Functions such as raster edits, checkboxes, Edit, Copy and Delete are not available.
Есть идеи о том, как это оптимизировать? не обязательно быть безумно быстрым прямо сейчас, замедляясь на 1 минуту.
Редактировать
Запуск объяснения по старому запросу
EXPLAIN SELECT * FROM kp_landing_page lp WHERE lp.parent = '7' AND ( SELECT COUNT(*) FROM kp_landing_page_product lpp WHERE lpp.landing_page_id = lp.landing_page_id AND lpp.productid = '6176' ) != 0
дает мне следующее
1 id PRIMARY select_Type lp table ALL type NULL possible_keys NULL keys NULL key_len NULL ref 233 rows Using where extra --- 2 DEPENDENT SUBQUERY lpp ref landing_page_id landing_page_id 4 kerstpakketonline.lp.landing_page_id 437 Using where
EDIT 2
some more information
this piece of code (PHP) is where the slowdown happens
$landingPages = array(); $qGetMainPages = $connection-gt;query("SELECT * FROM kp_landing_page WHERE parent = 0"); foreach ($qGetMainPages-gt;rows as $mainPage) { $qGetSubPages = $connection-gt;query(" SELECT lp.* FROM kp_landing_page lp WHERE lp.parent = '" . (int)$mainPage['landing_page_id'] . "' AND ( SELECT COUNT(*) FROM kp_landing_page_product lpp WHERE lpp.landing_page_id = lp.landing_page_id AND lpp.productid = " . (int)$row['productID'] . " ) != 0 "); foreach ($qGetSubPages-gt;rows as $subPage) { $landingPages[$mainPage['title']][] = $subPage['title']; } }
seems to be executing x amount of queries foreach product thus causing o(n) issues?
EDIT 3
using SHOW CREATE TABLE on both tables
— kp_landing_page_product
kp_landing_page_product CREATE TABLE kp_landing_page_product ( id int(11) NOT NULL AUTO_INCREMENT, landing_page_id int(11) NOT NULL, productid int(11) NOT NULL, PRIMARY KEY (id), KEY landing_page_id (landing_page_id), KEY productid (productid), CONSTRAINT landing_page_id_2 FOREIGN KEY (landing_page_id) REFERENCES kp_landing_page (landing_page_id) ON DELETE CASCADE ) ENGINE=InnoDB AUTO_INCREMENT=522630 DEFAULT CHARSET=utf8
— kp_landing_page
kp_landing_page CREATE TABLE kp_landing_page ( landing_page_id int(11) NOT NULL AUTO_INCREMENT, title varchar(255) COLLATE utf8mb4_bin NOT NULL, title_multi varchar(255) COLLATE utf8mb4_bin NOT NULL, rewrite varchar(255) COLLATE utf8mb4_bin NOT NULL, active tinyint(4) NOT NULL DEFAULT 1, parent int(11) NOT NULL DEFAULT 0, ordering int(11) NOT NULL, show_as_filter tinyint(4) NOT NULL DEFAULT 0, popular tinyint(4) NOT NULL DEFAULT 0, color_code varchar(255) COLLATE utf8mb4_bin NOT NULL, PRIMARY KEY (landing_page_id) ) ENGINE=InnoDB AUTO_INCREMENT=247 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
kp_landing_page_продукт содержит 160854 всего строк
страница kp_landing_page содержит всего 233 строки
kp_landing_page возвращает 9 строк с помощью этого SELECT * FROM kp_landing_page WHERE parent = 0
запроса
kp_landing_page_продукт возвращает около 40 строк с помощью этого
SELECT * FROM kp_landing_page lp WHERE lp.parent = '7' AND ( SELECT COUNT(*) FROM kp_landing_page_product lpp WHERE lpp.landing_page_id = lp.landing_page_id AND lpp.productid = '6176' ) != 0
запрос, это может измениться в зависимости от поставляемого продукта
Комментарии:
1. Что дает эту ошибку? Похоже, это не ошибка MySQL.
2. Если lp.parent является целым числом, почему вы используете
'7'
вместо просто 7?3. О чем говорит вам план выполнения? Может быть, вам не хватает индексов?
4. @ysth phpMyAdmin выдает эту ошибку
5. @SalmanA это просто потому, что запрос строится динамически с помощью PHP
Ответ №1:
Индексы:
lp: INDEX(landing_page_id) lpp: INDEX(landing_page_id, productid) -- either order is OK
Используйте EXISTS (он же «полу-соединение») вместо
AND ( SELECT COUNT(*) FROM kp_landing_page_product lpp WHERE lpp.landing_page_id = lp.landing_page_id AND lpp.productid = '6176' ) != 0
—gt;
AND EXISTS ( SELECT 1 FROM kp_landing_page_product AS lpp WHERE lpp.landing_page_id = lp.landing_page_id AND lpp.productid = '6176' )
EXISTS
остановится, когда будет найден первый; COUNT(*)
вероятно, придется проделать больше работы, чтобы узнать точное количество.
(Если вы хотите продолжить обсуждение, пожалуйста, укажите SHOW CREATE TABLE
две таблицы, размер каждой таблицы (приблизительное количество строк) и количество строк, возвращаемых запросом.)
Комментарии:
1. Эй, используй свой
AND EXISTS
… запрос выдает мне ошибку#1064 - There is something wrong in the syntax used at ''in line 5
, также я обновлю свой пост с вашей необходимой информацией2. Покажите мне запрос в том виде, в каком он у вас есть сейчас.
3. ` ВЫБЕРИТЕ * ИЗ страницы kp_landing_page lp, ГДЕ lp.parent = ‘» . $Главная страница[‘landing_page_id’] . «‘ И СУЩЕСТВУЕТ ( ВЫБЕРИТЕ 1 ИЗ kp_landing_page_product КАК lpp, ГДЕ lpp.landing_page_id = lp.landing_page_id И lpp.productid = ‘» . $строка[‘ProductID’]. «‘) `
4. I предложение WHERE перед в
AND EXISTS
противном случае я получил бы синтаксическую ошибку5. @nielsvanhoof — Нет.
WHERE
может иметь два «выражения»AND'd
вместе.EXISTS ( SELECT ... )
это «выражение». Должно быть, что-то еще не так. Давайте посмотрим запрос после того, как PHP закончит его сборку.