IgorPI
@IgorPI

На сколько может быть долгим запрос?

Здравствуйте коллеги!

Заказчик требует реализации метода, который бы выполнял клонирование некоторых записей.

Например:
На примере АЗС

Есть сеть заправок, их количество достигает 61 000 тыс.
Каждая заправка имеет ряд предоставляемых услуг.
Понятное дело, что это продажа разных видов топлива.

У каждой заправки свой перечень видов, это выглядит так:

Заправка А - 17
Заправка Б - 18

INSERT INTO `features` (`id`, `name`, `type`, `value`, `organization_id`) VALUES
	(36, 'Заправка', 'enum', NULL, 17),
	(71, 'Заправка', 'enum', NULL, 18);

INSERT INTO `features_values` (`id`, `feature_id`, `name`) VALUES
	(111, 71, 'Аи-92'),
	(115, 36, 'Аи-95'),
	(113, 36, 'Аи-98'),
	(112, 71, 'Дт');


Заказчик выбирает любую компанию и вносит корректив в перечень текущей компании.
И внимание! Что бы была опция для распространения корректива на все компании
Например всем 61 000 добавить условно "Пропан"

Для этого я написал функцию, ниже есть её реализация.
$features_repository->cloning($feature->getName(), $item);

Привожу пример функции.
Функция работает корректно, за исключением того, что его некоторая часть, достаточно дорога.
/**
     * @Rest\Route(
     *     path="/features.edit",
     *     methods={"POST"}
     * )
     * @param ObjectManager $manager
     * @param Request $request
     * @param RestMessage $restMessage
     * @return JsonResponse
     * @throws RestException
     * @throws DBALException
     */
    public function edit(ObjectManager $manager, Request $request, RestMessage $restMessage)
    {
        /** @var FeatureRepository $features_repository */
        $features_repository = $manager->getRepository("App:Feature");

        $feature = $features_repository->findOneBy([
                "id" => $request->get("feature_id", 0)]
        );

        if (!is_object($feature)) {
            RestError::exception(RestCode::RECORD_NOT_FOUND);
        }
        
        switch ($request->get("type", false)) {
            case "bool":
            {
                $feature->setType("bool");
                $feature->setName($request->get("name"));
                $feature->setValue($request->get("value"));
                foreach ($feature->getValues() as $value) {
                    $manager->remove($value);
                    $manager->flush();
                }
                $manager->persist($feature);
                break;
            }
            case "text":
            {
                $feature->setType("text");
                $feature->setName($request->get("name"));
                $feature->setValue($request->get("value"));
                foreach ($feature->getValues() as $value) {
                    $manager->remove($value);
                    $manager->flush();
                }
                $manager->persist($feature);
                break;
            }
            case "enum":
            {
                $feature->setType("enum");
                $feature->setName($request->get("name"));
                $feature->setValue($request->get(null));

                /** @var FeatureValue $old_fv */
                $not_persist = [];
                foreach ($feature->getValues() as $old_fv) {
                    $remove_old_fv = true;
                    foreach ($request->get("value", []) as $new_value) {
                        if ($new_value == $old_fv->getName()) {
                            $remove_old_fv = false;
                            $not_persist[] = $new_value;
                            break;
                        }
                    }

                    if ($remove_old_fv) {
                        $manager->remove($old_fv);
                        $manager->flush();
                    }
                }

                foreach ($request->get("value", []) as $item) {

                    foreach ($not_persist as $np) {
                        if ($item == $np) continue 2;
                    }

                    $feature_value = new FeatureValue();
                    $feature_value->setName($item);
                    $feature_value->setFeature($feature);

                    $feature->getValues()->add($feature_value);
                    $manager->persist($feature_value);

                    // Дорогой mysql запрос
                    if ($request->get("cloning", false)) {
                        $features_repository->cloning($feature->getName(), $item);
                    }
                }

                break;
            }

            default:
            {
                RestError::exception(RestCode::REQUEST_WITH_INVALID_PARAMETERS);
            }
        }

        $manager->flush();
        return $restMessage->success("Ok");
    }


Обратите внимание на комментарий "Дорогой mysql запрос"

Функция клонирования
/**
     * @param string $feature_name
     * @param string $feature_value_name
     * @throws DBALException
     */
    public function cloning(string $feature_name, string $feature_value_name)
    {
        $conn = $this->getEntityManager()->getConnection();
        $sql = "
            INSERT IGNORE INTO    features_values (`feature_id`, `name`)  (
                SELECT DISTINCT   f.id, :feature_value_name
                FROM              features f 
                LEFT JOIN         features_values fv 
                ON                f.id = fv.feature_id  
                WHERE             f.name = :feature_name AND f.`type` = :feature_type 
            );
        ";

        $stmt = $conn->prepare($sql);
        $stmt->execute([
            "feature_type" => EnumFeatureType::ENUM_TYPE,
            "feature_name" => $feature_name,
            "feature_value_name" => $feature_value_name
        ]);
    }


Схема
5ddcfec8834ad006782884.png

Самое главное, что таблица features_values будет содержать сотни миллионов записей ((

Что делать????
Форкать процесс, пусть себе живет сутки?

Ресурсы:
5ddc7f9e2f7f6796561751.png
  • Вопрос задан
  • 211 просмотров
Пригласить эксперта
Ответы на вопрос 3
VladimirAndreev
@VladimirAndreev
php web dev
А зачем в дорогом sql запросе вообще нужны feature_values?
Ответ написан
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
Зачем в вашем запросе нужен LEFT JOIN, результат которого нигде не используется?
Ответ написан
index0h
@index0h
PHP, Golang. https://github.com/index0h
Может лучше ввести понятие общих feature_values? А для конкретной заправки, если надо - добавлять запись с кастомными данными, либо флагом удаления.
Ответ написан
Ваш ответ на вопрос

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

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