• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Optymalizacja zapytań do bazy w integratorze

Object Storage Arubacloud
0 głosów
193 wizyt
pytanie zadane 26 kwietnia 2018 w PHP przez sc4rface Dyskutant (7,710 p.)

Cześć!

Napisałem integrator ofertowy, który jest mi niezbędny do prawidłowego śledzenia i ewentualnej aktualizacji, właczania oraz wyłączania ofert od poszczególnych providerów. Niestety - cholernie obciąża CPU, przez co raz - działa wolno, dwa - usługodawca poprosił mnie o jego optymalizację, ponieważ zbytnio obciążam serwer w jednym momencie, a skrypt powinien chodzić w cronie średnio co 10 minut.

Macie jakieś pomysły, jak mógłbym zoptymalizować zapytania tak, aby wszystko działało szybciej oraz mniej obciążało CPU? Z góry dzięki za wszystkie odpowiedzi, będę nagradzał plusikami :D

<?php

    include "config.php";

    function checkDevice($device) {

        if($device == "Android" || $device == "iOS" || $device == "iPhone" || $device == "iPad") {
            return true;
        } else {
            return false;
        }

    }

    function countUserPayout($providerPayout) {

        $summary = ($providerPayout * 100) / 2;
        return ceil($summary);

    }

    function getOgAds() {

        $response = file_get_contents("link");
        $result = json_decode($response, true);

        return $result["offers"];

    }

    function getAdGate() {

        $response = file_get_contents("link");
        $result = json_decode($response, true);

        return $result["data"];

    }

    function checkOgAdsDevice($devices) {

        $devicesArray = explode(",", $devices);

        foreach($devicesArray as $device) {

            if($device == "iPhone" || $device == "iPad" || $device == "Android") {
                return true;
            } else {
                return false;
            }

        }

    }

    function detectDesktop($category) {

        $categories = explode(",", $category);
        $exists = array_search("Desktop", $categories);

        if($exists) {
            return true;
        } else {
            return false;
        }

    }

    function createCountries($object) {

        foreach($object as $country) {

            $countries[] = $country;

        }

        if(isset($countries)) {
            return $countries;
        }

    }

    function createOfferWall() {

        $offerWall = [];

        foreach(getOgAds() as $offer) {

            if(checkOgAdsDevice($offer["device"]) && detectDesktop($offer["device"]) == false) {

                $offerWall[] = array(

                                    "offer_id" => $offer["offerid"],
                                    "name" => $offer["name_short"],
                                    "requirements" => $offer["adcopy"],
                                    "category" => $offer["device"],
                                    "provider_payout" => $offer["payout"], 
                                    "payout" => countUserPayout($offer["payout"]),
                                    "epc" => $offer["epc"],
                                    "icon" => $offer["picture"],
                                    "anchor" => $offer["link"],
                                    "countries" => (array)$offer["country"],
                                    "provider" => "ogads"

                                );

            } else {

                continue;

            }

        }

        foreach(getAdGate() as $offer) {

            if(checkDevice($offer["categories"][0])) {

                $offerWall[] = array(

                                    "offer_id" => $offer["id"], 
                                    "name" => $offer["adgate_rewards"]["anchor"],
                                    "requirements" => $offer["requirements"], 
                                    "category" => $offer["categories"][0],
                                    "provider_payout" => $offer["payout"],
                                    "payout" => countUserPayout($offer["payout"]),
                                    "epc" => $offer["epc"], 
                                    "icon" => $offer["creatives"]["icon"], 
                                    "anchor" => $offer["click_url"],
                                    "countries" => createCountries($offer["countries"]),
                                    "provider" => "adgate"

                                    );

            } else {

                continue;

            }

        }

        return $offerWall;

    }

    function createIdWall($dbh) {

        $offerWall = createOfferWall();

        foreach($offerWall as $offer) {

            $idWall[$offer["offer_id"]] = $offer["offer_id"];

        }

        return $idWall;

    }

    function setCountries($dbh, $countries, $offer) {

        if(isset($countries)) {
            foreach($countries as $country) {

                    $stmt = $dbh->prepare("INSERT INTO `table`(`aaa`,`xxx`,`yyy`) VALUES(NULL, :country, :oid)");
                    $stmt->bindParam(":country", $country, PDO::PARAM_STR);
                    $stmt->bindParam(":oid", $offer, PDO::PARAM_INT);
                    $stmt->execute();

            }
        }

    }

    function checkOfferExists($dbh, $providerId) {

        $stmt = $dbh->prepare("SELECT count(`id`) as `exists` FROM `table` WHERE `provider_id` = :providerId");
        $stmt->bindParam(":providerId", $providerId, PDO::PARAM_STR);
        $stmt->execute();

        $result = $stmt->fetch(PDO::FETCH_ASSOC);

        if($result["exists"] == 1) {
            return true;
        } else {
            return false;
        }

    }

    function getOfferInfo($dbh, $providerId) {

        $stmt = $dbh->prepare("SELECT * FROM `table` WHERE `provider_id` = :providerId");
        $stmt->bindParam(":providerId", $providerId, PDO::PARAM_STR);
        $stmt->execute();

        $result = $stmt->fetch(PDO::FETCH_ASSOC);
        return $result;

    }

    function compareOffers($dbh, $providerId, $offer) {

        $dbOffer = getOfferInfo($dbh, $providerId);

        if($dbOffer["provider_payout"] != $offer["provider_payout"] || $dbOffer["anchor"] != $offer["anchor"] || $dbOffer["offer_name"] != $offer["name"] || $dbOffer["category"] != $offer["category"] || $dbOffer["icon"] != $offer["icon"] || $dbOffer["requirements"] != $offer["requirements"]) {
            return true;
        } else {
            return false;
        }

    }

    function getDbOffers($dbh) {

        $stmt = $dbh->prepare("SELECT `provider_id` FROM `table`");
        $stmt->execute();

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

    }

    function activateOffer($dbh, $providerId) {

        $stmt = $dbh->prepare("UPDATE `table` SET `active` = 1 WHERE `provider_id` = :providerId");
        $stmt->bindParam(":providerId", $providerId, PDO::PARAM_INT);
        $stmt->execute();

    }

    function disableOffer($dbh, $providerId) {

        $stmt = $dbh->prepare("UPDATE `table` SET `active` = 0 WHERE `provider_id` = :providerId");
        $stmt->bindParam(":providerId", $providerId, PDO::PARAM_INT);
        $stmt->execute();

    }

    function updateOffer($dbh, $providerId, $offer) {

        $stmt = $dbh->prepare("UPDATE `table` SET 
                              `aaa` = :payout,
                              `bbb = :points,
                              `ccc` = :anchor,
                              `ddd` = :name,
                              `eee` = :category,
                              `fff` = :icon,
                              `ggg` = :requirements
                              WHERE `provider_id` = :providerId");

        $stmt->bindParam(":providerId", $providerId, PDO::PARAM_STR);
        $stmt->bindParam(":payout", $offer["provider_payout"], PDO::PARAM_INT);
        $stmt->bindParam(":points", $offer["payout"], PDO::PARAM_INT);
        $stmt->bindParam(":anchor", $offer["anchor"], PDO::PARAM_STR);
        $stmt->bindParam(":name", $offer["name"], PDO::PARAM_STR);
        $stmt->bindParam(":category", $offer["category"], PDO::PARAM_STR);
        $stmt->bindParam(":icon", $offer["icon"], PDO::PARAM_STR);
        $stmt->bindParam(":requirements", $offer["requirements"], PDO::PARAM_STR);

        $stmt->execute();

    }

    function addOffer($dbh, $offer) {

        $stmt = $dbh->prepare("INSERT INTO `table` (`aaa`, `bbb`, `ccc, `ddd`, `eee`, `fff`, `ggg`, `hhh`, `jjj`, `kkk`, `lll`, `zzz`, `xxx`) VALUES (NULL, :requirements, :points, :providerId, :icon, :epc, :ownPayout, :anchor, :category, :name, 1, 0, :provider);");
        $stmt->bindParam(":requirements", $offer["requirements"], PDO::PARAM_STR);
        $stmt->bindParam(":points", $offer["payout"], PDO::PARAM_INT);
        $stmt->bindParam(":providerId", $offer["offer_id"], PDO::PARAM_INT);
        $stmt->bindParam(":icon", $offer["icon"], PDO::PARAM_STR);
        $stmt->bindParam(":epc", $offer["epc"], PDO::PARAM_STR);
        $stmt->bindParam(":ownPayout", $offer["provider_payout"], PDO::PARAM_STR);
        $stmt->bindParam(":anchor", $offer["anchor"], PDO::PARAM_STR);
        $stmt->bindParam(":category", $offer["category"], PDO::PARAM_STR);
        $stmt->bindParam(":name", $offer["name"], PDO::PARAM_STR);
        $stmt->bindParam(":provider", $offer["provider"], PDO::PARAM_STR);
        $stmt->execute();

        setCountries($dbh, $offer["countries"], $offer["offer_id"]);

    }

    function checkStatus($dbh, $providerId) {

        $stmt = $dbh->prepare("SELECT `active` FROM `table` WHERE `provider_id` = :providerId");
        $stmt->bindParam(":providerId", $providerId, PDO::PARAM_INT);
        $stmt->execute();

        $result = $stmt->fetch(PDO::FETCH_ASSOC);

        if($result["active"] == 0) {
            return false;
        } else {
            return true;
        }

    }

    function followOffers($dbh) {

        foreach(createOfferWall() as $offer) {

            if(checkOfferExists($dbh, $offer["offer_id"])) {

                if(compareOffers($dbh, $offer["offer_id"], $offer)) {

                    updateOffer($dbh, $offer["offer_id"], $offer);

                } else {

                    continue;

                }

            } else {

                addOffer($dbh, $offer);

            }

        }

    }

    function findRevokeOffers($dbh) {

        $idWall = array_flip(createIdWall($dbh));

        foreach(getDbOffers($dbh) as $dbOffer) {

            $providerId = $dbOffer["provider_id"];

            if(isset($idWall[$providerId])) {

                continue;

            } else {

                if(checkStatus($dbh, $providerId)) {

                    disableOffer($dbh, $providerId);

                } else {

                    continue;

                }

            }

        }

    }

    function getCurrentTime() {

        $currentTime = date('Y-m-d H:i:s');
        return $currentTime;

    }

    echo "// START [".getCurrentTime()."]" .PHP_EOL;

    followOffers($dbh);
    findRevokeOffers($dbh);

    echo "// END" .PHP_EOL;

?>

 

1
komentarz 26 kwietnia 2018 przez Assasz Nałogowiec (30,460 p.)
if($exists) {
      return true;
} else {
      return false;
}

Co tu się odjanie... Nie lepiej np. tak?

return ($exists);

Analogicznie z innymi warunkami.

Podobnie z bindowaniem parametrów - można to zrobić jedną metodą zamiast 10.

$stmt->execute([
    ':foo' => $foo,
    ':bar' => $bar
    ...
]);

Optymalizację to ja bym zaczął od kodu ;)

komentarz 26 kwietnia 2018 przez sc4rface Dyskutant (7,710 p.)
Wpływa to w jakiś sposób na szybkość działania skryptu? Jeżeli nie - taki zapis jest dla mnie czytelniejszy.

@EDIT

Swoją drogą o takim bindowaniu wartości nie miałem wcześniej pojęcia. Napewno wykorzystam ;) Swoją drogą jak tutaj wykorzystać atrybut PDO::PARAM_INT na przykład, bo wiem że przechwytywanie wartości z argumentów funkcji do bindowania PDO tego wymaga.
1
komentarz 26 kwietnia 2018 przez Assasz Nałogowiec (30,460 p.)

If'y może niekoniecznie, choć jest przypadek, że warunek ternarny może nawet nieco spowolnić działanie skryptu - jeśli sprawdzana wartość jest bardzo duża - tutaj raczej nie ma takiej sytuacji. Jednak używanie pełnych if else w przypadku np. zwracania jedynie true / false jest nieco zbędne. Można też zrobić tak, aby zachować dobrą czytelność:

if ($condition) {
    # return przerywa interpretowanie skryptu
    return true;
}

return false;

PSR-2 w każdym razie nie stwierdza, jakie formy są dopuszczalne, a jakie nie.

W przypadku jednak bindowania parametrów - przy dużej liczbie zapytań może zajść odczuwalny wzrost wydajności, w końcu jest wykonywana jedna metoda zamiast powiedzmy 11 przy bindowaniu 10 parametrów, i to wszystko w pętli. 

Inaczej to wygląda, gdy zależy nam na jasnej kontroli typów - w przypadku execute([array]) wszystkie parametry są traktowane jako stringi. Można też zrobić tak:

# trzeci parametr ustawia długość stringa na 255 znaków
$stmt->bindParam(':foo', $foo, PDO::PARAM_STR, 255);

Zawsze można potestować :)

EDIT: No to lepiej użyć tradycyjnego bindowania. Chociaż szczerze powiedziawszy nie wiem jak to się ma do typów ustawionych w bazie. A performance może spaść.

komentarz 26 kwietnia 2018 przez sc4rface Dyskutant (7,710 p.)
Dzięki za rzeczowe informacje, nie omieszkam przetestować :D

1 odpowiedź

0 głosów
odpowiedź 26 kwietnia 2018 przez sc4rface Dyskutant (7,710 p.)
Tak btw. póki co deaktywowałem buforowanie zapytań PDO i obciążenie jest dużo mniejsze, co wychodzi na plus - aczkolwiek chciałbym jeszcze doszlifować ewentualną metodykę zapytań do SQL'a, żeby nie obciążać za bardzo bazy ciągłymi zapytaniami w pętli.
1
komentarz 26 kwietnia 2018 przez event15 Szeryf (93,790 p.)
Ogarnij sobie czym są transakcje w pdo.

Podobne pytania

0 głosów
1 odpowiedź 462 wizyt
pytanie zadane 11 listopada 2018 w PHP przez Śmieszek_;3 Użytkownik (780 p.)
0 głosów
1 odpowiedź 172 wizyt
pytanie zadane 13 stycznia 2020 w SQL, bazy danych przez reaktywny Nałogowiec (40,990 p.)
0 głosów
1 odpowiedź 755 wizyt
pytanie zadane 20 września 2016 w SQL, bazy danych przez Trucik Obywatel (1,130 p.)

92,572 zapytań

141,422 odpowiedzi

319,644 komentarzy

61,959 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...