Categories
Git

Կոդի upload-ի կազմակերկում shared հոսթինգի վրա

Գրեթե բոլոր ծրագրավորողները ունեն shared հոսթինգ, որի վրա պահում են իրենց անձնական կայքերը կամ ժամանակվոր նախագծեր որոնք հետո պետք է տեղափոխվեն հաճախորդի հոսթինգ։

Շատ հոսթինգներ ֆայլերը upoload անելու համար տալիս են միայն ftp տարբերակը, ինչը առաջացնում է բազմաթիվ խնդիրներ՝

  • պետք է հիշել որ ֆայլերի վրա ես փոփոխություն արել
  • տարբեր ֆոլդերներում արված փոփոխությունները շատ անհարմար է upload անել
  • ֆայլերը լոկալ ջնջելիս սերվերից չեն ջնջվում եթե առանձին չջնջես

Այս բոլորը բավականին դանդաղացնում էին աշխատանքը և հաճախ ցանկությունն էլ էր կորում փոփոխություններ անել։

Բայց այդ ամենը վերջացավ, երբ հայտնաբերեցի git-ftp plugin-ը git-ի համար։ Այն հնարավորություն է տալիս մեկ հրաման կանչելով կիրառել բոլոր commit արված փոփոխությունները FTP-ի միջոցով։

Նախագծի ավելացում git-ում

Նախ հարկավոր է ավելացնել նախագիծը git repository-ում, եթե այն դեռ այնտեղ չէ։ Ես օգտագործում եմ դրա համար GitLab-ը, բայց տարբերակները բազում են։

Git-FTP-ի ավելացում համակարգչում

Համակարգչում ավելացնելու համար հարկավոր է կանչէլ հետևյալ հրամանները՝

git clone https://github.com/git-ftp/git-ftp.git
cd git-ftp

# choose the newest release
tag="$(git tag | grep '^[0-9]*\.[0-9]*\.[0-9]*$' | tail -1)"

# checkout the latest tag
git checkout "$tag"
sudo make install

մանրամասն plugin-ի էջում։

Ստեղծել FTP account

Ձեր հոսթինգի ադմինիստրացիոն էջում (cPanel, Plesk, …) հարկավոր է գտնել FTP բաժինը և ավելացնել նոր account այն folder-ի համար որտեղ պետք է գտնվեն ֆայլերը։ Օրինակ cPanel-ում՝

FTP տվյալների ավելացում

Ավելացնում ենք ստեղծված account-ի տվյալները git-ի congif-ներում՝

git config git-ftp.url "ftp://ftp.domain-placeholder.am:21/public_html"
git config git-ftp.user "username"
git config git-ftp.password "pas$$word"

Առաջին կանչ

Առաջին կանչը շատ կարևոր է կախված նրանից ֆայլերը արդեն hosting-ում են թե ոչ։

Եթե ֆայլերը արդեն գտնվում են սերվերի անհրաժեշտ folder-ում, ապա պետք է համոզվել որ git-ում մեր ֆայլերը և սերվերի ֆայլերը չեն տարբերվում և կանչել՝

git ftp catchup

սերվերում կավելացվի նշում որ ֆայլերը ակտուալ են և այդ պահից հետո արված փոփոխությունները կհայտնվեն սերվերում։

Եթե սերվերի folder-ը դատարկ է պետք է կանչել՝

git ftp init

որից հետո բոլոր ֆայլերը upload կլինեն սերվեր։

Օգտագործում

Եթե առաջին կանչը հաջող ստացվեց հետագա փոփոխությունները կատարելիս պետք է commit անել և կանչէլ՝

git ftp push

Հրամանը upload կանի փոփոխված կամ նոր ստեղծված ֆայլերը և սերվերից կջնջի հեռացվածները։

Categories
Առանց կարգի

Join-ներ և lock-եր

Մենք մեր համակարգում ունեինք մի հարցում որը ուներ 20-ից ավել LEFT JOIN: Հարցումը աշխատում էր շատ արագ, քանի որ բոլոր table-ներին դիմում ենք Primary Key-ով։ Բայց ինչ-որ պահերի այդ հարցումը հայտնվում էր դանդաղ հարցումների ցանկում (slow log-ում): Բայց ավելի զարմանալի էր, որ այդ պահին նաև այլ թեթև հարցումներ էին հայտնվում դանդաղների շարքում։

Նախնական հետազոտությունները ցույց տվեցին, որ այդ բոլոր դանդաղած հարցումները արվում էին այն աղյուսակների վրա, որոնք կան մեր հիմնական մեծ հարցումում։

Մի-քիչ էլ փորեցինք և գտանք հետաքրիր փաստ։ Եթե աղյուսակը բլոկավորվում է (read/write lock) ապա նրա հետ բլոկավորվում են բոլոր այն աղյուսակները որոնցով այդ պահին արվում էր ընդհանուր հարցում։ Այսինքն եթե 20 LEFT JOIN ունեցող հարցման կատարման պահին աղյուսակներից մեկը բլոկավորվում էր ապա բլոկավորվում էին նաև մնացած 19ը:

JOIN-ները MySQL-ի (և ընդհանրապես SQL-ի) ուժեղագույն հնարավորություններից մեկն է, բայց միշտ պետք է հիշել, որ հարցումների ստաբիլության գրավականը նրանց պարզությունն է։

Ինչ արեցինք խնդիրը լուծելու համար

Առաջին հերթին բաժանեցինք հարցումը 2 մասի՝ ինֆորմացիայի մի մասը վերցնում էին մասթեր DB-ից իսկ մնացածը սլեյվից։ Երբ որ հարցումը ամբողջությամբ մասթերի վրա էր բացի դանդաղելուց առաջանում էին նաև նոր տողեր ավելացնելու հետ կապված խնդիրներ։

Հետագայում այն բաժանվելու է երեք մասի՝

  • մասթերից DB-ից վերցվող մաս
  • սլեյվից վերցվող մաս
  • քեշերից վերցվող մաս

դա JOIN-ների քանակը զգալի կպակասեցնի։

Հետո փոխեցինք isolation level-ը։ REPEATABLE_READ-ից փոխեցինք READ_COMMITED, դա կօգնի նվազեցնել lock-երի քանակը։

Categories
WordPress

WordPress-ի թարմացման կարևորությունը

Մեր WordPress-ով պատրաստված կայքերից մեկը կոտրել էին։ Բեռնել էին վնասակար ֆայլ և նրա միջոցով վարակել գրեթե բոլոր ֆայլերը։ Պահանջվեց մի քանի օր ամբողջը մաքրելու համար։

Փոխեցինք կայքի և սերվերի բոլոր գաղտնաբառերը, բայց երկու օր հետո խնդիրը կրկնվեց։ Պարզվեց պատճառը խոցելիություն ունեցող plugin-ներ։ Նրա միջոցով էր բեռնվել վնասակար ֆայլը։ Հետագա հետազոտությունը ցույց տվեց որ plugin-ի թերության մասին վաղուց հայտնի է և այն արդեն ուղղել են, սակայն կայքում մնացել էր հին տարբերակը։

WordPress-ը ունի ինքն իրեն ավտոմատ թարմացնելու հնարավորություն, սակայն նույնը տեղի չի ունենում plugin-ների համար։ Դրա համար շատ կարևոր է մշտապես թարմ պահել բոլոր plugin-ները և աշխատել հեռացնել այնպիսիները որոնք երկար ժամանակ չեն թարմացվում։

Ավելի մանրամասն թե ինչպես պաշտպանել ձեր WordPress կայքը կարող եք կարդալ Ինչպես ապահովել WordPress կայքի անվտանգությունը հոդվածում։

Ի դեպ WordPress-ը արդեն ունի plugin-ների ավտոմատ թարմացման հնարավորություն, սակայն ցանկալի է ինքնուրույն կատարել թարմացումները որպեսզի թարմացումից հետո համոզվել, որ կայքը ճիշտ է աշխատում։

Categories
PHP

Unicode email կցված ֆայլով

Phpmailer-ով SMTP միացումով email ուղարկելիս պարզվեց, որ հայերեն տառերը default կոնֆիգուրացիաներով սխալ են հասնում հասցեատիոջը:

Ուղարկում էինք հետևյալ ձևով՝

try {
    $mailer = new PHPMailer(true);
    $mailer->isSMTP(); // SMTP-ով
    $mailer->Host = 'mail.example.com'; // SMTP հոսթ
    $mailer->SMTPAuth = true; // ակտիվացնում ենք SMTP authorization-ը
    $mailer->Username = 'noreply@example.com'; // SMTP մուտքանուն
    $mailer->Password = 'V3RyStr0n9'; // SMTP գաղտնաբառ
    $mailer->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; // SSL-ի օգտագործում TLS-ի փոխարեն
    $mailer->Port = 465; // SSL-ի դեպքում 465 պորտը
    $mailer->isHTML();

    $mailer->setFrom('noreply@example.com', 'Some Example'); // ում անունից է ուղարկվում նամակը
    $mailer->addAddress('someone@aol.com'); // ստացողը
    $mailer->Subject = "Հայերեն տեքստ որի հետ խնդիր եղավ"; // Վերնագիր
    $mailer->Body = "<strong>Հայերեն տեքստ HTML տեգերով</strong>"; // HTML տեքստ
    $mailer->AltBody = "Հայերեն տեքստ առանց HTML տեգերի"; // մաքուր տեքստ

    //կցված ֆայլ
    if($_FILES['files']['tmp_name']["file_attached"]) {
        $mailer->addAttachment($_FILES['files']['tmp_name']["file_attached"], $_FILES['files']['name']["file_attached"]);
    }

    $mailer->send(); // ուղարկում ենք
}
catch (Exception $e){
    echo $e->getMessage();
}

Հայերեն տառերը նամակը ստացողի մոտ երևում էին հետևյալ կերպ՝

Տրամաբանական էր փոխել charset-ը UTF-8՝

 $mailer->CharSet = PHPMailer::CHARSET_UTF8; // utf-8

Դրանից հետո նամակները սկսեցին տեղ հասնել նորմալ տեսքով։ Բայց հայտնվեց նոր անսպասելի խնդիր, կցված ֆայլով նամակները ընդհանրապես տեղ չէին հասնում գրեթե բոլոր email համակարգերում։

Պարզվավ պատճառն այն է որ PhpMailer-ի default կոդավորման մեխանիզմն է 8bit, ինչը utf-8 charset-ի դեպքում սկսում է խնդիրներ տալ։ Լուծումը եղավ կոդավորումը փոխել 7bit-ի՝

$mailer->Encoding = PHPMailer::ENCODING_7BIT;

Դրանից հետո նամակները սկսեցին հասնել տեղ նորմալ կոդավորմամբ և բոլոր ֆայլերը կցված։

Categories
MySQL

Using join buffer-ի վտանգները

Block nested-loopնպատակն է MySQL-ին օգնել որոշ query-ներ ավելի արագ կատարել։

Պատկերացրեք մենք ունենք հետևյալ query-ն

SELECT t1.fieldA, t2.fieldB
FROM table1 t1
LEFT JOIN table2 t2 ON t2.id = t1.id_table2
WHERE t1.fieldC = ?
ORDER BY t1.id

Սովորական մշակման ժամանակ MySQL-ը գտնում է t1-ի անհրաժեշտ տողը և գտնում t2-ում պայմանին համապատասխանող տողը։

Սակայն լինում են դեպքեր երբ t2 աղյուսակում տողերի քանակը քիչ են լինում և MySQL-ը մտածում է «Ինչու՞ ամեն անգամ վերցնեմ t2-ի համապատասխան տողը եթե կարող եմ միանգամից վերցնել բոլոր տողերը, լցնել հիշողության մեջ և միանգամից այնտեղից օգտագործել։»

Ամեն ինչ հնչում է տրամաբանական, բայց կա մի «բայց»։

Բայց

Ինդեքսի մեջ տողերը պահվում են արդեն դասավորված և հարկավոր չի լինում լրացուցիչ գործողություններ կատարել նրանց դասավորելու համար։ Իսկ հիշողության մեջ պահվող աղյուսակի համար ինդեքսի դասավորումը հնարավոր չէ օգտագործել։ Ինչի հետևանքով MySQL-ը ստիպված է լինում նորից վերադասավորել տողերը, շատ հաճախ նաև ստեղծելով ժամանակավոր աղյուսակ, իսկ դա արդեն շատ ավելի դանդաղ գործողություն է։

Խոսքը գնում է query-ի հազարավոր անգամ ավելի դանդաղ աշխատելու մասին։

Իսկ ամենատխուրն այն է, որ MySQL-ը որոշում է օգտագործել join buffer-ը կախված աղյուսակներում տողերի քանակից, այսինքն սկզբում երբ գրվում է query-ն շատ դժվար է դա կանխատեսել։ Ուղակի մի լուսավոր օր քո պրոեկտը սկսում է չաշխատել առանց որևէ կոդի փոփոխության։

Լուծում

Ուսումնասիրությունների ըթացքում հասկացանք, որ ներկա պահին միակ ճիշտ լուծումն է անջատել այդ օպտիմիզացիան՝

SET GLOBAL optimizer_switch='block_nested_loop=off'

ՈՒՇԱԴՐՈՒԹՅՈՒՆ՝ Արդեն գործող պրոեկներում ասյ գործողությունը պետք է կատարել շատ մեծ զգուշությամբ։ Հնարավոր է որոշ query-ների անսպասելի արձագանք։

Categories
MySQL PHP

Integer-ները սիրում են ավարտվել

Մեր համակարգի արագ աճին զուգահեռ սկսեցինք հանդիպել դեպքեր, երբ մեր MySQL-ի autoincrement դաշտերը որոնք ունեն integer տիպ սկսեցին հասնել իրենց մաքսիմալ արժեքին։

Այդ ժամանակ MySQL-ը սկսում է վերադարձնել Duplicate entry '*' for key 'PRIMARY': Պատճառն էլ այն է, որ եթե դու ցանկանում ես դաշտում գրել թիվ, որը ավելի մեծ է քան մաքսիմալ արժեքը, ապա դրա փոխարեն MySQL-ը փորձում է դաշտում գրել այդ մաքսիմալ արժեքը։ Ստացվում է որ կատարվում է նոր տողի ավելացում id-ով որը արդեն կա։

Եթե տեսնում եք MySQL error, որոնց մեջ հանդիպում են 2147483647 կամ 4294967295 թվերը, ուրեմն հասել եք ձեր առավելագույն արժեքին

Խնդիրը լուծվեց monitoring-ի ավելացմամբ, որը ստուգում էր բոլոր աղյուսակների autoincrement-ի դաշտի առավելագույն արժեքը և ահազանգում եթե մոտենում ենք առավելագույն արժեքին։ Դրանով այս խնդրի մասին մոռացանք շատ երկար ժամանակով։

Ամեն ինչ լավ էր, բայց մի օր գիշերը ժամը 3ին մեր սերվերը սկսեց կախել։ Պատճառը մի query էր, որը մինչ այդ պահը բավակակնին թեթև էր աշխատում։ Explain-ը ոչ մի բան ցույց չտվեց, ամեն ինչ լավ էր, բայց query-ն աշխատում էր 20-30 վարկյանում նախատեսված 0.02 վարկյանի։

Մի քանի ժամ փնտրելուց հետո գտանք, որ պատճառը առավելագույնին հասած integer դաշտն էր, որը սակայն primary չէր և նրա համար ստուգումները չէին գործել։

table1.id դաշտը ստեղծվել էր biging, իսկ հարևան աղյուսակում table2.id_table1 դաշտը ստեղծվել էր integer: EXPLAIN-ը ցույց է տալիս որ ամեն ինչ լավ է, քանի որ ընդհանուր ինդեքսները ճիշտ էն, բայց մաքսիմալ արժեքից մեծ արժեքով query-ի դեպքում ինդեքսը չէր աշխատում։ Շատ տհաճ դեպք։

Եթե EXPLAIN- ով ամեն ինչ լավ է բայց query-ն դանդաղ է աշխատում ապա համոզվեք որ խնդիրը սխալ արժեքների մեջ չէ։

Լուծումը գտնվեց սքրիփթի մեջ, որը ժամանակ առ ժամանակ ստուգում է բոլոր ինդեքսավորված ֆիլդերի առավելագույն արժեքները։

Եթե ինչ որ մեկին պետք է կկցեմ սքրիփթը այստեղ։

<?php
define("DB_HOST", "mysql-5.7.ddk");
define("DB_PORT", "3306");
define("DB_NAME", "city");
define("DB_USER", "root");
define("DB_PASS", "password");

function q($sql, $values = [])
{
    global $pdo;
    try {
        $stm = $pdo->prepare($sql);
        $stm->execute($values);
        return $stm->fetchAll(PDO::FETCH_OBJ);
    } catch (PDOException $e) {
        echo "Exception: {$e->getMessage()}\n";
        exit(1);
    }
}

$pdo = false;
try {
    $pdo = new PDO(
        'mysql:host=' . DB_HOST . ';port=' . DB_PORT,
        DB_USER,
        DB_PASS);
} catch (PDOException $e) {
    echo "Exception: {$e->getMessage()}\n";
    exit(1);
}

// Վերցնում ենք մեր բազայի բոլոր աղյուսակների բոլոր դաշտերը
$sql = "
    SELECT c.*, t.TABLE_ROWS
    FROM information_schema.columns c
             LEFT JOIN information_schema.tables t ON t.TABLE_NAME = c.TABLE_NAME AND t.TABLE_SCHEMA = c.TABLE_SCHEMA
    WHERE c.TABLE_SCHEMA = ?
      AND t.TABLE_TYPE = 'BASE TABLE';
";

$fields = q($sql, [DB_NAME]);

if ($fields === false) {
    echo "Can't select fields\n";
    echo "*****\n";
    exit(1);
}

foreach ($fields as $field) {
    // Եթե դաշտը int տիպի է
    if ($field->DATA_TYPE === 'int') {
        // Եթե դաշտը ինդեքսավորված է
        if ($field->COLUMN_KEY) {
            // առանց նշան դաշտերի համար մաքսիմալ արժեքն է 4294967295 իսկ նշանով դաշտերի համար 2 անգամ քիչ
            $length = stripos($field->COLUMN_TYPE, 'unsigned') !== false ? 4294967295 : 2147483647;

            // վերցնում ենք դաշտի առավելագույն արժեքը
            $max = q("SELECT MAX(`{$field->COLUMN_NAME}`) AS m FROM `{$field->TABLE_NAME}`");
            $max = $max ? $max[0]->m : 0;

            $percent = round($max / $length, 1) * 100;
            // համեմատում ենք արժեքը ընտտրած մինիմալ արժեքի հետ, որից սկսած համարում ենք որ խնդիր ունենք
            if ($percent > $percent_check) {
                // ԱՅՍՏԵՂ ԱՎԵԼԱՑՆՈՒՄ ԵՆՔ ԱՅՆ ԳՈՐԾՈՒՂՈՒԹՅՈՒՆԸ ՈՐԸ ՊԵՏՔ Է ԱՆԵԼ ՄԱՔՍԻՄԱԼ ԱՐԺԵՔԻՆ ՀԱՍՆԵԼՈՒ ԴԵՊՔՈՒՄ
            }
        }
    }
}

echo "Finished!\n";
Categories
MySQL

Ինչպես արագ պաշտպանվել SQL injection-ից

SQL-injection-ից պաշտպանվլեու ՄԻԱԿ ճիշտ տարբերակը placeholder-ներ օգտագործելն է։ Վերջ։


Բայց պատկերացրեք, որ կա արդեն աշխատող մեծ պրոեկտ, որում կան պոտենցիալ injection-ի հնարավորություններ։ Դա նույնպես պետք է լուծել placeholder-ներով, բայց դա երկար պրոցես է։ Քանի դեռ զբաղվում եք դրանց ավելացմամբ կարող եք մի հետաքրքիր լուծում անել։

Մեկ ընդհանուր միացումը տվյալների բազային փոխարինում ենք 2 առանձին միացումների՝ տվյալները կարդալու և փոփոխելու համար։ Դրանից հետո բոլոր կարդալու query-ները ուղարկում եք կարդալու միացումով իսկ փոփոխելունը փոփոխելու։

Հիմնականում տվյալների փոփոխությունը ավելի քիչ քանակությամբ տեղերում է իրականանում քան ինֆորմացիայի կարդալը և հետևաբար ավելի հեշտ է դրանց անվտանգությունը ապահովել։

Այս գործողությամբ դուք չեք ապահովագրի ձեր ինֆորմացիան գողանալուց, բայց առնվազն կապահովագրեք կորուստից։

ՈՒՇԱԴՐՈՒԹՅՈՒՆ. 2 միացումը լրացուցիչ բեռ է սերվերների վրա

ԱՆՊԱՅՄԱՆ խորհրդակցեք ձեր սերվերի ադմինների հետ, եթե ունեք։
Categories
MySQL

Ծանր SELECT-ը բաժանում ենք 2 թեթևի

Լինում են դեպքեր երբ մեր MySQL հարցումը ծանր է աշխատում և EXPLAIN֊ը ցույց է տալիս, որ հարցումը կատարելու համար օգտագործվել է ժամանակավոր աղյուսակ (Using temporary) և հավանաբար rows դաշտում նույնպես կտեսնեք բավականին մեծ թիվ, ինչը ժամանակավոր աղյուսակի ստեղծման հետ համատեղ բերում է հարցման դանդաղ աշխատանքին։

Այս խնդրի լուծման միակ ճիշտ տարբերակն է ժամերով տանջվել, գտնել ժամանակավոր աղյուսակ ստեղծելու պատճառը և փոփոխել հարցումը։ Բայց դիտարկենք տարբերակը երբ պատճառը գտել ենք բայց անհնար է այն լուծել կամ չենք էլ փորձել գտնել, որովհետև վեր ենք այդ ամենից։

Պատկերացնենք թե ունենք նման հարցում՝

SELECT t1.title, t2.long_field
FROM table1 t1
LEFT JOIN table2 t2 ON t2.id = t1.id_table1
WHERE t1.date BETWEEN '2018-09-01' AND '2018-09-15'
LIMIT 20

Իմ հանդիպած դեպքում table1-ից մոտ 200K տող էր մշակվում իսկ t2.long_field դաշտը բավականին մեծ էր և  MySQL-ը ստիպված ժամանակավոր աղյուսակ էր ստեղծում այդ 200K տողի համար։

Մի քանի օրից մենք գտանք որ պատճառը այդ դաշտն էր և հեռացրինք այն մեր հարցումից, բայց մինչ գտնելը փոփոխեցինք հարցումը անխափան աշխատանքը ապահովելու համար։

Առանձին հարցումով վերցրեցինք այդ 20 տողի id-ները՝

SELECT t1.id
FROM table1 t1
LEFT JOIN table2 t2 ON t2.id = t1.id_table1
WHERE t1.date BETWEEN '2018-09-01' AND '2018-09-15'
LIMIT 20

id-ները վերցնելու համար MySQL-ը կարիք չունի նույնիսկ դիմելու աղյուսակին, այդ ինֆորմացիան նա վերցնում է հենց ինդեքսից, այսինքն ժամանակավոր աղյուսակի կարիքը վերանում է։

Ուշադրություն

Այստեղ բերված բոլոր պնդումները հիմնված են ենթադրության վրա, որ բոլոր աղյուսակներին մենք դիմում ենք ինդեքսներով

Ստացված արդյունքները մշակում ենք մեր կոդում և վերցնում id-ները։ Դրանից հետո անում ենք մեր սկզբնական հարցումը ուղակի WHERE պայմանը փոխարինում ենք մեր id-ներով՝

SELECT t1.title, t2.long_field
FROM table1 t1
LEFT JOIN table2 t2 ON t2.id = t1.id_table1
WHERE t1.id IN (/*ստացված id-ների ցուցակը*/)
LIMIT 20

Ինչպես և նախնական հարցումում այս դեպքում էլ կստեղծվի ժամանակավոր աղյուսակ բայց տողերի քանակը կլինի ոչ թե 200K այլ 20։ Տողերի քանակը պակասեց տաս հազար անգամ, տարբերությունը զգալի է, համաձայնվեք։

Այս երկու հարցումը իրար հետ միասին հարյուրավոր (եթե ոչ հազարավոր) անգամ ավելի արագ է աշխատում քան մեկ սկզբնականը։

Կարող եք նաև 2 հարցման փոխարեն id-ները ստանալ subquery-ով, բայց ես աշխատում եմ խուսափել subquery-երից։

Եթե ունեք կասկածելի հարցում կարող եք գրել մեկնաբանությունում և մենք կփորձենք միասին գտնել խնդիրը։

Categories
PHP

Ամսաթվերի համեմատություն PHP-ում

Հաճախ հարկավոր է լինում համեմատել 2 ամսաթիվ և շատ հաճախ այդ ամսաթվերը լինում եմ Y-m-d կամ Y-m-d H:i:s ֆորմատների։

Դիցուք (:D) ունենք 2 փոփոխական՝

$date1 = "2018-09-08 18:19:20";
$date2 = "2018-09-01 20:25:25";

Առաջ համեմատելու համար ես անում էի՝

<?php
$date1_stamp = strtitime($date1);
$date2_stamp = strtitime($date2);
if($date1_stamp > $date2_stamp){
    //Գործողություն
}

կամ

<?php
$date1_obj = new \DateTime($date1);
$date2_obj = new \DateTime($date2);

if($date1_obj > $date2_obj){
    //Գործողություն
}

Իսկ հետո պարզվեց մի հետաքրքիր փաստ՝ նման ֆորմատի ամսաթվերը կարելի է համեմատել առանց որևէ մշակման։

<?php
if($date1 > $date2){
    //Գործողություն
}

Նման համեմատությունը ավելի արագ է և կոդը դարձնում է հեշտ ընթեռնելի։

Categories
MySQL

INSERT … SELECT-ը չարիք է

MySQL-ում մի աղյուսակից մյուսը ինֆորմացիա կրկնօրինակելու համար ամենարագ տարբերակն է՝

INSERT INTO `table1` (`field1`, `field2`, `field3`)
SELECT `field1`, `field2`, `field3`
FROM `table2`
WHERE `id` = 8

Գայթակղությունը մեծ է նման կերպ ինֆորմացիա կրկնօրինակել, խուսափելով կոդ գրելուց և տվյալների բազային 2 հարցում անելուց։ Բայց մի՛ շտապեք։ Կա մի շաա՜տ ՄԵԾ խնդիր։

InnoDB աղյուսակների ամենահայտնի առավելություններից է նոր տողերի ավելացումը առանց աղյուսակի բլոկավորման։ Սակայն INSERT ... SELECT անելիս SELECT-ի մեջ կանչվող բոլոր աղյուսակները բլոկավորվում են մինչև հարցումի ավարտը։

Հարցումների ընդհանուր քանակի փոքր խտության դեպքում այդ բլոկավորումը կարող է անցնել աննկատ, բայց մի֊փոքր ավել բեռնվածություն և ձեր պրոեկտը արդեն չի ախատում։

Ինպե՞ս խուսափել

Ամեն ինչ շատ պարզ է։ Առանձին անում ենք ինֆորմացիան ստանալու հարցումը, մշակում ենք արժեքները կոդի մակարդակում, պատրաստում ենք ներմուծման հարցումը:

INSERT-ը միայնակ չէ

Ես օրինակը բերեցի INSERT ... SELECT-ի մասին, բայց նույնը վերաբերվում է UPDATE ... JOIN և DELETE ... JOIN հարցումներին։

Հիշե՛ք

Տվյալների բազայից ինֆորմացիա վերցնելը և ինֆորմացիա փոփոխելը ՄԻՇՏ պետք է լինեն առանձին հարցումներով։ 

Ջնջելու՞ եք հին արժեքները

Եթե կրկնօրինակելուց հետո պատրաստվում եք ջնջել տողերը սկզբնական աղյուսակից ապա ջնջեք միայն id-ով։

Ցանկացած այլ ստուգումով ջնջելը կարող է բերել նրան որ ջնջած տողերը չեն համապատասխանի կրկնօրինակված տողերին։