@perchikooko

Как это превратить в один запрос?

Передо мной стоит задача оптимизации запросов:
этим запросом я проверяю количество записей удовлетворяющих условию

select * from Products where product_id=$p_id and region=$key

этот запрос если количество записей не равно нулю

update Products set prices_purchase=$p_purchase, prices_selling=$p_selling, prices_discount=$p_discount where product_id=$p_id and region=$key;

а это уже если равно

INSERT INTO Products (product_id, region, prices_purchase, prices_selling, prices_discount)
VALUES ('$p_id', '$key', '$p_purchase', '$p_selling', '$p_discount')

Вопрос заключается в том как это соединить в один запрос (у меня получается только два), не получилось с if exists, а также insert into ... on duplicate key update. Желательно чтобы был готовый вариант (если не затруднит поясните).
  • Вопрос задан
  • 151 просмотр
Пригласить эксперта
Ответы на вопрос 2
@stavfz
Скажите а "select * from Products where product_id=$p_id and region=$key" Может вернуть больше одной записи за один проход?
Не пойму просто логическую суть условия if ($smth->num_rows!=0)
если задача найти именно дублирующиеся записи то по идеи должно быть if ($smth->num_rows>1) т.к. 1 строка это не дубликат. Получается что в Select как таковом отпадает всякая нужна просто update и всё (есть что обновить обновит нету нет) и если в самой таблице настроить уникальность по двум полям то можно следом и insert делать, он все равно не задвоит данные.

по вашему примеру получается что update можно делать и если больше одной записи в базе соответсвует выборке ваше условие !=0 предполагает что нужно обновить все записи которые соответсвуют выборке сколько бы их в базе не было
Есть ещё такая штука как replace, работает также как инсерт если в базе найдется запись которая совпадет по значению первичных ключей (если product_id и region у вас являются таковыми) со вставляемой строкой то произойдет Update
Опять возвращаемся к тому что сложно посоветовать что то конкретное не видя структуру таблицы её ключей и индексов
Вполне вероятно что в вашем случае просто вместо конструкций из if можно написать:
$sql = "REPLACE INTO Products (product_id, region, prices_purchase, prices_selling, prices_discount)
        VALUES ('$p_id', '$key', '$p_purchase', '$p_selling', '$p_discount')";


p.s.
то что пишу ниже это офтоп но не совсем, вы спрашивали "Можете посоветовать что можно изменить в коде"
Могу.
Строить запросы так как это делаете Вы неправильно с точки зрения безопасности, правильно было бы сделать так:
для INSERT
$sql = "INSERT INTO Products
SET
product_id= :product_id, 
region= :region, 
prices_purchase= :prices_purchase, 
prices_selling= :prices_selling, 
prices_discount= :prices_discount
";
// подготовка запроса
$stmt = $this->bd_connect->prepare($sql);

// привязываем значения
$stmt->bindParam(':product_id',$p_id);
$stmt->bindParam(':region',$key);
$stmt->bindParam(':prices_purchase',$p_purchase);
$stmt->bindParam(':prices_selling',$p_selling);
$stmt->bindParam(':prices_discount',$p_discount);

//Выполняем запрос
$stmt->execute()


Для SELECT
$sql = "SELECT * FROM Products 
WHERE product_id= :p_id AND region= :key";

// подготовка запроса
$stmt = $this->bd_connect->prepare($sql);

// привязываем значения
$stmt->bindParam(':p_id',$p_id);
$stmt->bindParam(':key',$key);

// выполняем запрос
$stmt->execute();
 
 // получаем количество строк
$num = $stmt->rowCount();

// одним из распространенных вариантов получаем значения (смотри php PDO)
$row = $stmt->fetch(PDO::FETCH_ASSOC);


Перед привязкой значений можно а часто даже нужно дополнительно обработать ( слеши там всякие и т.п. :) ), то, что собираешься биндить
Ответ написан
gzhegow
@gzhegow
aka "ОбнимиБизнесмена"
Да не, в данном случае все правильно что апдейт и инсерт это разные запросы. Есть там конечно ON DUPLICATE KEY UPDATE, условный UPSERT, но здесь скорость проседает не поэтому.

А потому что в таблице многовато индексов и проверок и вероятно вы закачиваете сразу 10 тыщ и ему пока проиндексируешь всё - время надо. Разбейте по 500 и если не хочется ждать выведите Step: 1-500, Step: 500-1000 и тд.

В mysql базе можно временно выключить индексы SET UNIQUE_CHECKS/SET FOREIGN_KEY_CHECKS/SET AUTOCOMMIT, и в документации работы с Bulk (пачка) даже рекомендация такая есть их выключать, а после запроса включать обратно.

Но еще может проседать потому, что как раз наоборот индексов мало - то есть выборка через критерий оббегает всю здоровенную таблицу, чтобы найти нужные записи, в этом случае РАНЬШЕ в запросе находится поле которое МАКСИМАЛЬНО уменьшит результат, а ПОЗЖЕ - остальные. И на том поле которое уменьшит результат стоит индекс, чтобы вся база не прочесывалась, а проверка по нем происходила не по таблице, а по "алфавитному указателю" этой таблицы (зачем читать всю книгу, если можно смотреть заглавие?)
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы