Pull to refresh

Эффективный алгоритм обработки больших баз данных MLM-структур

Level of difficultyMedium
Reading time6 min
Views2.4K

Приветствую Вас, уважаемые читатели! Сегодня хочу поделиться с вами информацией об эффективном алгоритме для обработки больших баз данных MLM-структур, который усовершенствует подход к анализу и управлению данными в многоуровневом маркетинге.

Введение

Многоуровневый маркетинг (MLM) является популярной бизнес-моделью, основанной на сети дистрибьюторов для роста компании. С расширением сети управление клиентами MLM и их взаимоотношениями становится все более сложным, что делает важным поиск эффективного решения для управления постоянно растущим объемом данных. В этой статье мы рассмотрим инновационный подход к обработке больших баз данных MLM-структур, который позволяет оптимизировать анализ и управление данными.

Традиционные методы обработки данных vs представленный алгоритм

Традиционные методы обработки данных в MLM, такие как рекурсивные функции, часто оказываются медленными и неэффективными, особенно при работе с большими объемами данных. Это может привести к длительным задержкам в обработке информации, что негативно сказывается на оперативности и эффективности работы компании.

Допустим, у нас есть бинарная MLM-структура с 10 миллионами пользователей и 23 уровнями. Стандартный подход к обработке таких структур заключается в использовании рекурсивных функций, что может занять значительное время и ресурсы сервера.

Например, для выборки всех пользователей на 23-м уровне с использованием рекурсии. Сложность рекурсии оценивается как O(n * h), где n — количество пользователей на уровне, а h — высота дерева. В данном случае, это равно 2^23 * 24 ≈ 201,326,592 операций. (в которые входят и SQL запросы), что займет очень много времени, даже на мощных серверах. Компания которая обращалась ко мне для оптимизации базы данных, расчеты проводила раз в день по ночам чтобы не прерывать основную работу. Ощутимые задержки вычислений начинаются уже после 50000 пользователей даже на оптимизированной базе данных.

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

id |iduser| id_rek| road        | level
---|------|-------|-------------|-----
1  | 1    | 0     | |1|         | 1
2  | 2    | 1     | |1|2|       | 2
3  | 3    | 1     | |1|3|       | 2
4  | 4    | 2     | |1|2|4|     | 3
5  | 5    | 2     | |1|2|5|     | 3
6  | 6    | 3     | |1|3|6|     | 3

Теперь мы основную нагрузку перекладываем на SQL запросы (запрос с LIKE не самый эффективный, но по сравнению с рекурсивными методами значительно выигрывает), которые выполняются значительно быстрее и нагляднее, пример на php, одним запросом находит всех последователей пользователя id-3 в порядке иерархии, тогда как рекурсией нам бы пришлось с корневого id обойти всех пользователей.

<?php 

class MLMTree {
    private $db;

    public function __construct($db) {
        $this->db = $db;
    }

    public function getAllDescendants($rootUserId) {
        $query = "SELECT * FROM users WHERE road LIKE CONCAT('%|', :root_user_id, '|%') AND id != :root_user_id ORDER BY level";
        $stmt = $this->db->prepare($query);
        $stmt->bindValue(':root_user_id', $rootUserId, PDO::PARAM_INT);
        $stmt->execute();

        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
}

// Пример использования
$db = new PDO('mysql:host=localhost;dbname=mlm_database;charset=utf8', 'username', 'password');
$mlmTree = new MLMTree($db);
$rootUserId = 3;

$descendants = $mlmTree->getAllDescendants($rootUserId);
print_r($descendants);

?>

Пример класса пользователя на php, на его основе Вы можете создать свой вариант, по данной методике можно реализовать практически все варианты и виды MLM структур.

<?php

class User
{
    private $pdo;

    public function __construct($pdo)
    {
        $this->pdo = $pdo;
    }

    public function find($userId)
    {
        $sql = "SELECT * FROM users WHERE id = :id";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute([':id' => $userId]);
        return $stmt->fetch(PDO::FETCH_ASSOC);
    }

    public function create($data)
    {
        $sql = "INSERT INTO users (username, email, password, id_rek) VALUES (:username, :email, :password, :id_rek)";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute([
            ':username' => $data['username'],
            ':email' => $data['email'],
            ':password' => $data['password'],
            ':id_rek' => $data['id_rek']
        ]);
        $userId = $this->pdo->lastInsertId();

        // Create corresponding tree entry
        $this->createTreeEntry($userId, $data['id_rek']);
    }

    private function createTreeEntry($userId, $id_rek)
    {
        if ($userId == 1) {
            $sql = "INSERT INTO tree (id_user, id_rek, col, lvl, road) VALUES (1, 0, 0, 1, '|1|')";
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute();
        } else {
            $sql = "SELECT * FROM tree WHERE road LIKE CONCAT('%|', :id_rek, '|%') ORDER BY lvl, col ASC";
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute([':id_rek' => $id_rek]);
            $treeRow = $stmt->fetch(PDO::FETCH_ASSOC);

            if ($treeRow) {
                $road = $treeRow['road'] . $userId . "|";
                $lvl = count(explode("|", $road)) - 2;

                $sql = "INSERT INTO tree (id_user, id_rek, col, lvl, road) VALUES (:id_user, :id_rek, 0, :lvl, :road)";
                $stmt = $this->pdo->prepare($sql);
                $stmt->execute([
                    ':id_user' => $userId,
                    ':id_rek' => $id_rek,
                    ':lvl' => $lvl,
                    ':road' => $road
                ]);

        $sql = "UPDATE tree SET col = col + 1 WHERE id_user = :id_rek";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute([':id_rek' => $id_rek]);
    }
}
    }

    public function delete($userId)
    {
        $user = $this->find($userId);
        if ($user) {
            $sql = "DELETE FROM users WHERE id = :id";
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute([':id' => $userId]);

            $this->deleteTreeEntry($userId, $user['id_rek']);
            $this->updateRoadsAfterDeletion($userId, $user['id_rek']);
            $this->updateRekIdAfterDeletion($userId, $user['id_rek']);
        }
    }

    private function deleteTreeEntry($userId, $id_rek)
    {
        $sql = "DELETE FROM tree WHERE id_user = :id_user";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute([':id_user' => $userId]);

        $sql = "UPDATE tree SET col = col - 1 WHERE id_user = :id_rek";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute([':id_rek' => $id_rek]);
    }

    private function updateRoadsAfterDeletion($userId, $id_rek)
    {
        $sql = "UPDATE tree SET road = REPLACE(road, '|$userId|', '|'), lvl = lvl - 1 WHERE road LIKE '%|$userId|%'";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute();
    }
    private function updateRekIdAfterDeletion($userId, $id_rek)
    {
        $sql = "UPDATE users SET id_rek = :id_rek WHERE id_rek = :user_id";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute([':id_rek' => $id_rek, ':user_id' => $userId]);

        $sql = "UPDATE tree SET id_rek = :id_rek WHERE id_rek = :user_id";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute([':id_rek' => $id_rek, ':user_id' => $userId]);
    }
    public function getUsersByLevel($level)
{
    $sql = "SELECT tree.*, users.username, users.email, users.password FROM tree 
            JOIN users ON tree.id_user = users.id
            WHERE tree.lvl = :level";
    $stmt = $this->pdo->prepare($sql);
    $stmt->execute([':level' => $level]);
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
}

    
    public function getUsersByRekId($rekId)
    {
        $sql = "SELECT * FROM tree WHERE id_rek = :rek_id";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute([':rek_id' => $rekId]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
    
    // ... другие методы, если необходимо ...
}
?>

Преимущества нового алгоритма

  1. Ускорение обработки данных: благодаря использованию параллельной древовидной структуры, алгоритм позволяет значительно ускорить процесс обработки информации, сокращая время выполнения запросов.

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

  3. Упрощение процесса управления данными: новый алгоритм предоставляет интуитивно понятный и организованный способ анализа и управления данными MLM-структур, что облегчает работу администраторов и менеджеров.

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

  2. Экономия ресурсов: использование нового алгоритма позволяет снизить нагрузку на сервера и сетевые ресурсы, что сказывается положительно на стабильности системы и снижает затраты на обслуживание.

Подведем итоги

Мы рассмотрели эффективный алгоритм обработки больших баз данных MLM структур и привели примеры его реализации на PHP. Этот подход позволяет значительно сократить время обработки данных и упростить управление MLM структурами.

Вместо использования рекурсии и тяжеловесных запросов, мы предложили способ работы с данными на основе построенного готового пути, что позволяет ускорить выборку информации и облегчить нагрузку на сервер.

Надеемся, что данная статья поможет вам в решении задач, связанных с MLM структурами и позволит оптимизировать процессы ваших проектов. В случае возникновения дополнительных вопросов или предложений, буду рад вашим комментариям и обсуждениям. Удачи вам в реализации вашего MLM проекта!

Исходные коды примеров лежат на https://github.com/infosave2007/fastmlm

Tags:
Hubs:
Total votes 8: ↑7 and ↓1+11
Comments24

Articles