Ablakok.  Vírusok.  Jegyzetfüzetek.  Internet.  hivatal.  Segédprogramok.  Drivers

Sokféle SQL lekérdezésről írtam már, de itt az ideje, hogy bonyolultabb dolgokról is beszéljünk, például egy SQL lekérdezés, amellyel több táblából is lehet rekordokat kiválasztani.

Amikor egy táblázatból válogattunk, minden nagyon egyszerű volt:

SELECT kívánt_mezőnevek FROM tábla_neve WHERE kiválasztási_feltétel

Minden nagyon egyszerű és triviális, de ha egyszerre több táblázatból választunk, minden kicsit bonyolultabbá válik. Az egyik nehézség a mezőnevek egybeesése. Például minden táblának van azonosítómezője.

Vegyünk egy ilyen kérést:

SELECT * FROM tábla_1, tábla_2 WHERE tábla_1.azonosítója > tábla_2.felhasználói_azonosítója

Sokak számára, akik még nem foglalkoztak ilyen lekérdezésekkel, úgy tűnik, hogy minden nagyon egyszerű, ha azt gondolják, hogy csak a táblák nevei kerültek ide a mezők neve elé. Valójában ez elkerüli az azonos mezőnevek közötti ütközéseket. A bonyolultság azonban nem ebben, hanem egy ilyen SQL lekérdezés algoritmusában van.

A munka algoritmusa a következő: az első rekord a_1 táblából származik. Ennek a bejegyzésnek az azonosítója a_1 táblából származik. Továbbá a táblázat_2 teljesen kinéz. És minden olyan rekord hozzáadásra kerül, ahol a user_id mező értéke kisebb, mint a kiválasztott rekord azonosítója a_1 táblázatban. Így az első iteráció után 0-tól végtelen számú rekord lehet. A következő iteráció során a tábla_1 következő rekordját veszik fel. A teljes tábla_2. tábla ellenőrzése újra megtörténik, és a táblázat_1.azonosító > táblázat_2.felhasználói_azonosító kijelölési feltétele ismét aktiválódik. Minden rekord, amely megfelel ennek a feltételnek, hozzáadódik az eredményhez. A kimenet hatalmas számú rekord lehet, sokszorosa mindkét tábla teljes méretének.

Ha az első alkalom után megérted, hogyan működik, akkor nagyszerű, de ha nem, akkor olvass, amíg teljesen meg nem érted. Ha ezt megérted, akkor könnyebb lesz.

Az előző SQL-lekérdezést, mint olyant, ritkán használják. Csak a többtáblás kiválasztási algoritmus magyarázatára adták. És most elemezzünk egy zökkenőmentesebb SQL-lekérdezést. Tegyük fel, hogy két táblánk van: termékekkel (van egy tulajdonos_id mező, amely a terméktulajdonos azonosítójáért felelős) és felhasználókkal (van egy id mező). Az összes rekordot egyetlen SQL-lekérdezéssel szeretnénk megszerezni, és úgy, hogy mindegyik információt tartalmazzon a felhasználóról és az egyetlen termékéről. A következő bejegyzés ugyanarról a felhasználóról és a következő termékéről tartalmazott információkat. Ha ennek a felhasználónak az árui elfogynak, lépjen a következő felhasználóhoz. Így össze kell kapcsolnunk két táblát, és olyan eredményt kell kapnunk, amelyben minden rekord információt tartalmaz a felhasználóról és az egyik termékéről.

Egy ilyen lekérdezés 2 SQL lekérdezést vált ki: külön kiválasztással a termékeket tartalmazó táblázatból és a felhasználókat tartalmazó táblázatból. Ezenkívül egy ilyen kérés azonnal megfelel a felhasználónak és termékének.

Maga a kérés nagyon egyszerű (ha megértette az előzőt):

SELECT * FROM felhasználók, termékek WHERE user.id = products.owner_id

Az algoritmus itt már egyszerű: az első rekordot a felhasználók táblájából veszik. Ezután a rendszer veszi az azonosítóját, és elemzi a termékek tábla összes rekordját, hozzáadva az eredményhez azokat, amelyek tulajdonosa_azonosítója megegyezik a felhasználók tábla azonosítójával. Így az első iteráció során az első felhasználó összes terméke összegyűjtésre kerül. A második iterációnál a második felhasználó összes áruja összegyűjtésre kerül, és így tovább.

Mint látható, az SQL lekérdezések több táblából történő kiválasztáshoz nem a legegyszerűbbek, de a hasznuk óriási lehet, ezért nagyon kívánatos az ilyen lekérdezések ismerete és használata.

2008. október 9., 23:37 MySQL lekérdezés optimalizálás
  • MySQL

A mindennapi munkában a lekérdezések írása során meglehetősen hasonló hibákkal kell megküzdenie.

Ebben a cikkben arra szeretnék példákat mondani, hogyan NE írjunk lekérdezéseket.

  • Az összes mező kiválasztása
    SELECT * FROM táblázat

    Lekérdezések írásakor ne jelöljön ki minden mezőt - "*". Csak azokat a mezőket sorolja fel, amelyekre valóban szüksége van. Ez csökkenti a lekért és elküldött adatok mennyiségét. Ne feledkezzünk meg az indexek fedezéséről sem. Még ha valóban szüksége van a táblázat összes mezőjére, a legjobb, ha felsorolja őket. Először is javítja a kód olvashatóságát. Csillag használatakor lehetetlen megtudni, hogy mely mezők vannak a táblázatban anélkül, hogy megnéznénk. Másodszor, idővel változhat a táblázat oszlopainak száma, és ha ma öt INT oszlop, akkor egy hónap múlva TEXT és BLOB mezők kerülhetnek fel, ami lelassítja a kijelölést.

  • Kérések ciklusban.
    Világosan meg kell értenie, hogy az SQL egy olyan nyelv, amely halmazokon működik. Néha a programozók, akik hozzászoktak ahhoz, hogy eljárási nyelveken gondolkodjanak, nehezen tudják átstrukturálni gondolkodásukat a halmazok nyelvén. Ez egyszerűen megtehető egy egyszerű szabály elfogadásával – "soha ne hajtson végre lekérdezéseket ciklusban". Példák arra, hogyan lehet ezt megtenni:

    1. Minták
    $hírazonosítók = get_list("SELECT news_id A mai_hírekből ");
    while($hírazonosító = get_next($news_ids))
    $hírek = get_row("SELECT title, body FROM news WHERE news_id = ". $hírazonosító);

    A szabály nagyon egyszerű - minél kevesebb kérés, annál jobb (bár ez alól is vannak kivételek, mint minden szabálynál). Ne felejtsük el az IN() konstrukciót. A fenti kód egy lekérdezéssel írható:
    SELECT cím, törzs FROM today_news BELSŐ CSATLAKOZÁS Hírek HASZNÁLATA(hír_azonosító)

    2. Betétek
    $log = parse_log();
    while($rekord = next($log))
    query("INSERT INTO naplók SET value = ". $log["value"]);!}

    Sokkal hatékonyabb egyetlen lekérdezés ragasztása és végrehajtása:
    INSERT INTO naplók (érték) ÉRTÉKEK (...), (...)

    3. Frissítések
    Néha több sort is frissítenie kell ugyanabban a táblázatban. Ha a frissített érték megegyezik, akkor minden egyszerű:
    UPDATE news SET title="test" WHERE id IN (1, 2, 3).!}

    Ha a módosítandó érték minden bejegyzésnél eltérő, akkor ezt a következő lekérdezéssel lehet megtenni:
    UPDATE hírek SET
    cím = CASE
    WHEN news_id = 1 THEN "aa"
    WHEN news_id = 2 THEN "bb" VÉGE
    WHERE news_id IN (1, 2)

    Teszteink azt mutatják, hogy egy ilyen lekérdezés 2-3-szor gyorsabb, mint több különálló lekérdezés.

  • Műveletek végrehajtása indexelt mezőkön
    SELECT user_id FROM felhasználók WHERE blogok_száma * 2 = $érték

    Ez a lekérdezés akkor sem használ indexet, ha a blogs_count oszlop indexelve van. Az index használatához nem kell átalakításokat végrehajtani a lekérdezés indexelt mezőjén. Ilyen kérések esetén helyezze át a konverziós függvényeket egy másik részre:
    SELECT user_id FROM felhasználók WHERE blogok_száma = $érték / 2;

    Hasonló példa:
    SELECT user_id FROM felhasználók WHERE TO_DAYS(CURRENT_DATE) - TO_DAYS(regisztrált) = DATE_SUB(CURRENT_DATE, INTERVAL 10 DAY);
    akarat.

  • A sorok lekérése csak a számuk megszámlálásához
    $eredmény = mysql_query("SELECT * FROM table", $link);
    $szám_sorok = mysql_szam_sorok($eredmény);
    Ha ki kell választania egy bizonyos feltételnek megfelelő sorok számát, használja a SELECT lekérdezés COUNT(*) FROM FROM ahelyett, hogy az összes sort kijelölné, csak hogy megszámolja őket.
  • Extra sorok lekérése
    $eredmény = mysql_query("SELECT * FROM table1", $link);
    while($row = mysql_fetch_assoc($eredmény) && $i< 20) {

    }
    Ha csak n mintasort szeretne, használja a LIMIT értéket ahelyett, hogy elvetné a további sorokat az alkalmazásban.
  • Az ORDER BY RAND() használata
    SELECT * FROM tábla ORDER BY RAND() LIMIT 1;

    Ha a táblázat több mint 4-5 ezer sorból áll, akkor az ORDER BY RAND () nagyon lassan fog működni. Sokkal hatékonyabb lesz két lekérdezés futtatása:

    Ha a táblázat auto_increment" elsődleges kulcsés nincs passz
    $rnd = rand(1, query("SELECT MAX(id) FROM table"));
    $row = query("SELECT * FROM table WHERE id = ".$rnd);

    Vagy:
    $cnt = query("SELECT COUNT(*) FROM FROM");
    $row = query("SELECT * FROM table LIMIT ".$cnt.", 1");
    ami azonban lassú is lehet a táblázat nagyon sok sorával.

  • Használat egy nagy szám CSATLAKOZÁS
    KIVÁLASZTÁS
    v.video_id
    egy név,
    g.műfaj
    TÓL TŐL
    videók AS v
    BAL CSATLAKOZÁS
    link_actors_videos AS la ON la.video_id = v.video_id
    BAL CSATLAKOZÁS
    szereplők AS a ON a.actor_id = la.actor_id
    BAL CSATLAKOZÁS
    link_genre_video AS lg ON lg.video_id = v.video_id
    BAL CSATLAKOZÁS
    műfajok AS g ON g.genre_id = lg.genre_id

    Emlékeztetni kell arra, hogy ha a táblákat egy a többhez kapcsolják, a kijelölésben lévő sorok száma minden következő JOIN-nál nőni fog. hasonló esetek gyorsabb egy ilyen kérést több egyszerűre bontani.

  • LIMIT használatával
    KIVÁLASZTÁS... A táblázatból LIMIT $kezdet, $oldalonként

    Sokan azt gondolják, hogy egy ilyen lekérdezés $per_page rekordokat ad vissza (általában 10-20), és ezért gyorsan működik. Gyorsan működik az első néhány oldalon. De ha a rekordok száma nagy, és egy SELECT ... FROM table LIMIT 1000000, 1000020 lekérdezést kell végrehajtania, akkor egy ilyen lekérdezés végrehajtásához a MySQL először kiválaszt 1000020 rekordot, eldobja az első milliót, és 20-at ad vissza. egyáltalán ne legyen gyors. Nincsenek triviális módszerek a probléma megoldására. Sokan egyszerűen korlátozzák a rendelkezésre álló oldalak számát ésszerű számra. Az ilyen lekérdezések felgyorsítása fedőindexek vagy harmadik féltől származó megoldások (pl. szfinx) használatával is lehetséges.

  • Nem használja az ON DUPLICATE KEY UPDATE
    $row = query("SELECT * FROM table WHERE id=1");

    Ha($sor)
    query("UPDATE table SET oszlop = oszlop + 1 WHERE id=1")
    más
    query("INSERT INTO table SET oszlop = 1, id=1");

    Egy hasonló konstrukció egyetlen kéréssel helyettesíthető, feltéve, hogy az id mezőben van elsődleges vagy egyedi kulcs:
    INSERT INTO tábla SET oszlop = 1, id=1 ON DUPLICATE KEY UPDATE oszlop = oszlop + 1

Olvas

Az utolsó órán egy kellemetlenséggel találkoztunk. Amikor tudni akartuk, hogy ki hozta létre a "kerékpárok" témát, és ennek megfelelő lekérdezést tettünk:

A szerző neve helyett az azonosítóját kaptuk. Ez érthető is, mert lekérdeztünk egy táblát - Témák, és a téma szerzőinek neveit egy másik táblában tároltuk - Users. Ezért, miután megtanultuk a téma szerzőjének azonosítóját, még egy lekérdezést kell végrehajtanunk - a Felhasználók táblába, hogy megtudjuk a nevét:

Az SQL lehetőséget biztosít az ilyen lekérdezések összekapcsolására úgy, hogy az egyiket részlekérdezéssé (beágyazott lekérdezéssé) alakítja. Tehát, hogy megtudjuk, ki hozta létre a "kerékpárok" témát, a következő lekérdezést hajtjuk végre:

Vagyis a kulcsszó után AHOL, még egy lekérdezést írunk a feltételbe. A MySQL először az allekérdezést dolgozza fel, visszaadja az id_author=2 értéket, és ezt az értéket adja át a záradéknak AHOL külső kérés.

Egy lekérdezésben több allekérdezés is lehet, egy ilyen lekérdezés szintaxisa a következő: Vegye figyelembe, hogy az allekérdezések csak egy oszlopot választhatnak ki, amelynek értékeit visszaadják a külső lekérdezésnek. Ha több oszlopot próbál kijelölni, az hibát eredményez.

Tegyünk még egy konszolidációs kérést, nézzük meg, milyen üzeneteket hagyott a fórumon a „bicikli” téma szerzője:

Most bonyolítjuk a feladatot, nézzük meg, mely témákban hagyott üzenetet a „kerékpárok” témakör szerzője:

Lássuk, hogyan működik.

  • A MySQL először a legmélyebb lekérdezést hajtja végre:

  • Az eredmény (id_author=2) egy külső kérésnek lesz átadva, amely a következő formában jelenik meg:

  • Az eredmény (id_topic:4,1) egy külső lekérdezéshez kerül átadásra, amely a következő formában lesz:

  • És ez adja a végeredményt (topic_name: horgászatról, horgászatról). Azok. a "kerékpárok" témakör szerzője üzeneteket írt a Szergej által létrehozott "A horgászatról" témában (id=1) és a Sveta által létrehozott "A horgászatról" témában (id=4).
Valójában csak ennyit akartam mondani a beágyazott lekérdezésekről. Két pontra azonban figyelni kell:
  • Nem ajánlott háromnál nagyobb beágyazási szinttel rendelkező lekérdezéseket létrehozni. Ez a végrehajtási idő növekedéséhez és a kód észlelésének bonyolultságához vezet.
  • A beágyazott lekérdezések adott szintaxisa a leggyakoribb, de korántsem az egyetlen. Például kérés helyett

    ír

    Azok. bármilyen operátort használhatunk kulcsszó HOL (az utolsó leckében tanulmányoztuk őket).

Ez a rövid cikk az adatbázisokra, különösen a MySQL-re, a mintavételre és a számlálásra összpontosít. Adatbázisokkal való munka során gyakran meg kell számolni a COUNT() sorok számát bizonyos feltétellel vagy anélkül, ez rendkívül egyszerűen megtehető a következő lekérdezéssel

Kód megtekintése MySQL

A lekérdezés egy értéket ad vissza a táblázatban lévő sorok számával.

Feltételes számolás

Kód megtekintése MySQL

A lekérdezés egy értéket ad vissza a táblázatban a megadott feltételnek megfelelő sorok számával: var = 1

Ha több sorszám-értéket szeretne kapni különböző feltételekkel, végrehajthat egyenként több lekérdezést, pl.

Kód megtekintése MySQL

De bizonyos esetekben ez a megközelítés nem praktikus és nem optimális. Ezért egy lekérdezés szervezése válik relevánssá, több részlekérdezéssel, hogy egy lekérdezésben egyszerre több eredményt kapjunk. Például

Kód megtekintése MySQL

Így egyetlen lekérdezés végrehajtásával az adatbázisban olyan eredményt kapunk, amely több feltétel szerint számolja a sorok számát, amelyek több számláló értéket tartalmaznak, pl.

Kód megtekintése SZÖVEG

c1|c2|c3 -------- 1 |5 |8

Az allekérdezések használatának hátránya a több különálló lekérdezéshez képest a végrehajtás sebessége és az adatbázis terhelése.

Az egyetlen MySQL-lekérdezésben több COUNT-ot tartalmazó lekérdezés következő példája kissé eltérő szerkezetű, IF(feltétel, érték1, érték2) konstrukciók, valamint SUM() összegzés segítségével. Lehetővé teszi, hogy egyetlen lekérdezésben meghatározott kritériumok szerint válasszon adatokat, majd összegezze azokat, és ennek eredményeként több értéket jelenítsen meg.

Kód megtekintése MySQL

Ahogy a lekérdezésből is látszik, elég tömören van felépítve, de a végrehajtás sebessége sem tetszett, az eredmény adott kérés lesz a következő

Kód megtekintése SZÖVEG

összesen|c1|c2|c3 --------------- 14 |1 |5 |8

Ezután összehasonlító statisztikát adok három lekérdezési lehetőség végrehajtási sebességéről több COUNT () kiválasztásához. A lekérdezés végrehajtási sebességének tesztelésére minden típusból 1000 lekérdezést hajtottak végre, több mint háromezer rekordot tartalmazó táblával. Ugyanakkor minden alkalommal, amikor a lekérdezés SQL_NO_CACHE-t tartalmazott, hogy letiltja az eredmények adatbázis általi gyorsítótárazását.

Végrehajtási sebesség
Három külön kérés: 0,9 mp
Egy kérés segédlekérdezésekkel: 0,95 mp
Egy kérés IF és SUM konstrukcióval: 1,5 mp

Következtetés. Így számos lehetőségünk van lekérdezések létrehozására az adatbázisban MySQL adatok több COUNT() esetén az első opció külön lekérdezéssel nem túl kényelmes, de a sebesség szempontjából a legjobb eredményt adja. A második lehetőség az allekérdezésekkel valamivel kényelmesebb, de a végrehajtási sebessége valamivel alacsonyabb. És végül a lekérdezés IF és SUM konstrukciókat tartalmazó harmadik tömör változata, amely a legkényelmesebbnek tűnik, a legalacsonyabb végrehajtási sebességgel rendelkezik, ami majdnem kétszer alacsonyabb, mint az első két lehetőség. Ezért az adatbázis működésének optimalizálásakor javaslom a második lekérdezési opciót, amely COUNT ( ) allekérdezéseket tartalmaz, egyrészt a végrehajtási sebessége közel áll a leggyorsabb eredményhez, másrészt egy ilyen szervezés egyetlen lekérdezésben meglehetősen kényelmes.

Ha hibát észlel, jelöljön ki egy szövegrészt, és nyomja meg a Ctrl + Enter billentyűket
OSSZA MEG: