Отражение оптимизации производительности: уменьшите количество запросов к БД и разумно используйте переменные-члены.

задняя часть PHP
Отражение оптимизации производительности: уменьшите количество запросов к БД и разумно используйте переменные-члены.

«Это 28-й день моего участия в ноябрьском испытании обновлений. Подробную информацию об этом событии см.:Вызов последнего обновления 2021 г."

Я уже составлял статью об отражении оптимизации производительности:Не манипулируйте БД в цикле for, отзыв не плохой, продолжайте пользоваться性能优化В качестве темы поделитесь недавними краткими мыслями:Уменьшите количество запросов к БД и разумно используйте переменные-члены.

高内聚,低耦合Это очень популярная дизайнерская идея.Достигая высокой сплоченности и низкой связанности, мы должны также учитывать проблему передачи значений: мы должны избегать необоснованной передачи значений при извлечении функций и инкапсуляции кода, а также избегать нескольких функций.Неоднократно запрашивать одну и ту же базу данных.

796e4519341baf05f5edf63bec328d2a.jpeg

взять каштан

Описание требования

  1. Наш проект представляет собой приложение для знакомств. В нем есть такие действия, как смахивание карточек «Нравится», «Дизлайк» и «Суперлайк», а также такие действия, как дарение подарков и приглашение на свидание.

  2. Существуют различные суждения для вышеуказанных действий, такие как верхний предел лайков каждый день, и является ли он участником или нет; при дарении подарков необходимо судить, активирован ли участник, и использовать ли цену членства при вычете гонораров, при приглашении на свидание необходимо судить, друг ли это и т. д. И т. д. Различные, казалось бы, обыденные сценарии объединяются, чтобы сделать структуру кода невероятно сложной. Программирование стало чрезвычайно важным.

  3. Если вам не нужно беспокоиться о том, чтобы смотреть вниз, вы можете сначала подумать о том, как бы вы это реализовали, если бы вас попросили заняться программированием.

...

Подумайте об этом, чтобы лучше понять следующие дизайнерские идеи, или введите свое решение в поле для комментариев.

...

анализ спроса

  1. Исходя из вышеперечисленных требований, определим несколько понятий: действие, потребление, запись;

  2. Сплит-действия: основные действия, платежные действия, глобальные действия, сплит-потребление: пополнение, потребление, купоны и т. д.;

  3. Реализовать логический код в соответствии с концепцией разделения, например, базовое действие абстрагируется в класс, а платежное действие и глобальное действие наследуют этот класс: платежное действие абстрагируется в один класс, а связанное с оплатой действие действия размещаются здесь; глобальное действие относится к независимо от того, является ли оно членом или нет, является ли оно потребителем или нет, действия, которые могут выполняться, также абстрагируются в отдельный класс.

(В первой версии разработки проекта мы не делали такой абстракции. Различные действия, потребление и записи были реализованы в классе. По мере развития проекта он становился очень раздутым и хаотичным.)

Вышеизложенное может быть немного абстрактным, но приведенный ниже пример кода сделает его намного яснее~

пример кода

Чтобы быть компактным и понятным каждому, я не буду вставлять наш логический код напрямую, а вынесу ключевые сегменты кода для анализа.

весь кадр

  1. Следующий код упоминается выше全局动作类, который наследует基础动作类, все действия в基础动作类определено в
  2. стандартизированный输入参数и输出参数эти переменные-члены
  3. Метод построения передает текущий идентификатор пользователя и идентификатор контрагента, все действия должны иметь обе стороны
  4. стандартизированныйsetAction()установить действие,getActionResult()Получите результат выполнения действия, унифицируйте формат и спецификацию ввода и вывода и следуйте унифицированной спецификации независимо от того, где она вызывается.
class UserUniversalAction extends BaseUserAction
{
    //输入参数
    protected $_userid;      //当前用户ID
    protected $_actionId;    //动作ID
    protected $_extra = [];       //动作携带的额外参数
    protected $_otherUserid; //对方用户ID
    protected $_data = [];        //中间存储
    protected $_houseOpen = [];
    protected $_userConsume = null;
    protected $_now;

    //输出参数
    protected $_pass = true;            //财务性约束,有没有消费通过
    protected $_rechargeType = null;    //消费的类型
    protected $_propCount = 0;
    protected $_consumeSuccess = false; //消费成功-默认false
    protected $_canInvite = false;      //
    protected $_errorCode = 0;          //非财务行约束,动作的关系执行条件
    protected $_needAfterAction = true;
    //protected $_out = [];               //动作执行完成后,输出结果

    public $hasRight = false;
    
    public function __construct($userid, $otherUserid = '')
    {
        parent::__construct($userid, 0);
        $this->_otherUserid = $otherUserid;
        //初始化参数
        $this->_houseOpen = HouseOpen::getCurrentOpen();
        //消费初始化
        $this->_userConsume = new UserConsume($this->_userid);
        $this->_now = time();
    }

    //设置执行动作
    public function setAction($actionId, $extra = [])
    {
        //设置动作参数
        $this->_actionId = $actionId;
        $this->_extra = $extra;

        //前置动作,执行权限校验等
        $this->_beforeAction();
        //只有非财务性约束和财务性约束通过后,才能继续执行
        if ($this->_errorCode == 0 && $this->_pass) {
            //执行动作
            $this->_actionExecute();
            if ($this->_errorCode == 0) {
                //后置动作
                $this->_afterAction();
            }
        }
    }

    //获取动作执行结果
    public function getActionResult()
    {
        return [
            //财务性限制
            'pass' => $this->_pass,
            'rechargeType' => $this->_rechargeType,
            'propCount' => $this->_propCount,
            'canInvite' => $this->_canInvite,
            //业务性限制
            'errorCode' => $this->_errorCode,
            'out' => $this->_data
        ];
    }

Подробное объяснение настройки действий выполнения

Внимательные одноклассники, возможно, обнаружили: мы снова правыsetAction()После дальнейшей разборки он делится на:

_beforeAction: предварительное действие, проверка разрешения на выполнение и т. д. Например, только когда участник открыт, разрешено суперлайк, и только когда вы становитесь другом, вам разрешено пригласить свидание.

_actionExecute: выполнить действие, например поставить суперлайк, например отправить собеседнику приглашение на свидание.

_afterAction: Публикация действия, например отправка сообщения панели уведомлений другой стороне при начале встречи; например, отправка push-сообщения, чтобы проинформировать другую сторону об опыте знакомства после завершения встречи.

Преимущество этого в том, чтоисключительно ясно, почти все действия можно понимать как три шага: до действия, во время действия и после действия.

Еще одно хардкорное место — это второй параметр, передаваемый в$extra = []:

Первый переданный параметр легко понять:$actionIdЭто идентификатор действия, который мы определили, и мы судим, какие действия выполнять в соответствии с идентификатором действия.

второй параметр$extra = [], extra — это концепция расширенных параметров и переменных параметров. как я упоминал в началеУменьшите количество запросов к БД и разумно используйте переменные-членыЭто перекликается:

Параметры, которые необходимо использовать в нескольких местах, передаются, а не получаются каждый раз путем запроса к БД. Данные, которые мы передаем в качестве параметров, могут быть назначены переменным-членам.

    //设置执行动作
    public function setAction($actionId, $extra = [])
    {
        //设置动作参数
        $this->_actionId = $actionId;
        $this->_extra = $extra;

        //前置动作,执行权限校验等
        $this->_beforeAction();
        //只有非财务性约束和财务性约束通过后,才能继续执行
        if ($this->_errorCode == 0 && $this->_pass) {
            //执行动作
            $this->_actionExecute();
            if ($this->_errorCode == 0) {
                //后置动作
                $this->_afterAction();
            }
        }
    }

Хардкорная часть, обратите внимание

b4f752eebd5491b6ccd0990d8c697134.jpeg

Дружеское напоминание Сяо Укуна:文章有点长,硬核部分开始了,请同学们坚持一会,认真看。

Следующий пример кода поможет вам лучше понять如何合理的使用成员变量

Старые правила сначала говорят о спросе: сделайте вывод в конце встречи, если время голосовой онлайн-встречи составляет менее 1 минуты, пользователь получит компенсацию за ваучер на встречу (мы думаем, что время встречи меньше, чем 1 минута). 1 минута, это плохой опыт, и пользователи не могут тратить деньги зря, чтобы дать купонную компенсацию)

Если это обычный дизайн: нам нужно запросить БД не менее 3 раз, а именно:

  1. Когда инициируется завершение встречи, состояние изменяется, выполняется серия операций чтения и записи, и последнее состояние данных возвращается клиенту.
  2. существует_afterAppointmentFinishЗапросите, открыта ли голосовая комната (наш продукт имеет бизнес-концепцию, только в бизнесе может выполнять действия по назначению)
  3. существует_afterAppointmentFinishВ соответствии с идентификатором даты запросите дату и другую информацию обеих сторон.

Передавая параметры через переменные-члены, вам нужно только один раз запросить БД, то есть:

  1. Когда инициируется завершение встречи, состояние изменяется, выполняется ряд операций, и клиенту возвращается последнее состояние данных.$this->_data = $appointmentModel->toArray();присвоить переменной-члену;_afterAppointmentFinish()прошедший$this->_dataПросто возьмите значение.
   protected function _actionExecute()
   {
        //执行权限校验
        switch ($this->_actionId) {
              .
              .
              .
            case self::TYPE_ACTION_END:
                $this->_doAppointmentEndActionExecute();
                break;
        }
    }
    
    protected function _afterAction()
    {
        //动作后置操作
        switch ($this->_actionId) {
            .
            .
            .
            case self::TYPE_ACTION_END:
                $this->_afterAppointmentFinish();
                break;
            default:
        }
    }
    
    protected function _doAppointmentEndActionExecute()
    {
        $appointmentModel = AppointmentInfo::query()->selectRaw('id,userid,"inviteeUserid",status,endtime,"callStartTimestamp","callDuration","isConsume","appointmentOpenId"')
            ->where('id', $this->_extra['appointmentId'])->first();
        .
        .
        .
        $appointmentModel->endtime = time();
        $appointmentModel->status = AppointmentInfo::TYPE_STATUS_END;
        $appointmentModel->save();
        $this->_data = $appointmentModel->toArray();
        .
        .
        .
    }
        
    protected function _afterAppointmentFinish()
    {
        $houseOpen = $this->_houseOpen; //减少1次DB查询
        if ($houseOpen['status'] != HouseOpen::HOUSE_STATUS_OPEN) {
            return false;
        }
        //减少2次DB查询
        if (isset($this->_data)
            && $this->_data['isConsume'] == AppointmentInfo::TYPE_IS_CONSUME
            && $this->_data['appointmentOpenId'] == $houseOpen['currentAppointmentOpenId']
            && $this->_data['callDuration'] < 60) { //约会时长不足1分钟,花了多少补偿多少精酿券
            .
            .
            .
            }
        }
    }

Вышеупомянутое просто каштан.По мере развития проекта количество сценариев применения увеличивается.Разумное использование переменных-членовбудет отражать более высокое значение.

обзор

Давайте рассмотрим входные параметры, которые я упомянул в начале, этоПеременные-члены_extra ,_data ,_houseOpenВсе они представляют собой массивы, которые легко расширить.Мы можем разумно использовать переменные-члены, чтобы уменьшить избыточные запросы к БД и повысить эффективность работы программы.

    //输入参数
    protected $_userid;      //当前用户ID
    protected $_actionId;    //动作ID
    protected $_extra = [];       //动作携带的额外参数
    protected $_otherUserid; //对方用户ID
    protected $_data = [];        //中间存储
    protected $_houseOpen = [];
    protected $_userConsume = null;
    protected $_now;

Суммировать

Вы должны знать, что каждый запрос к БД занимает много времени в сети; мы храним данные в переменных-членах, а время, затрачиваемое на чтение данных из памяти, незначительно.

Добро пожаловать на взаимодействие

Время летит так быстро, сегодня 29-е, и сегодня я наконец-то завершил 28-дневное испытание обновления этого месяца.

Надеюсь, что в будущем я напишу больше таких статей, как сегодня. Эта заключительная статья относительно хардкорная, по крайней мере, в ней нет воды, и ее можно рассматривать как идеальное завершение задачи ноябрьского обновления.

Спасибо за поддержку! ! ! Добро пожаловать в три волны подряд~

1fda3718df4635061fe8bca8aec99870.jpeg

Рекомендация хардкорной статьи

Резюме PHP to Go в середине 2021 года

Как получить ошибку интерфейса в первый раз? Не нужно тестировать девушку, а потом расспрашивать, не завис ли ваш интерфейс.

Git использует настоящий бой: совместная разработка с участием нескольких человек, руководство по работе с Git для срочного исправления онлайн-ошибок.

Отражение оптимизации производительности: не используйте БД в цикле for

Отражение оптимизации производительности: не используйте расширенную версию БД в цикле for

Наконец

👍🏻: Если вы чувствуете, что что-то приобрели, пожалуйста, поставьте лайк, чтобы поощрить это!

🌟: Любимые статьи для удобного просмотра!

💬: Обменивайтесь комментариями и развивайтесь друг с другом!