Ruby on Rails programinės įrangos kūrimas. Indeksai v2
Damianas Watroba
Software Engineer
Dirbdami su Ruby on Rails sistema, paprastai dirbame su reliacinėmis duomenų bazėmis, pavyzdžiui, "MySQL" arba "PostgreSQL". Apibrėždami perkėlimus naudojant "Active Record Migrations", susiduriame su vadinamaisiais indeksais, tačiau pradedantieji dažnai ne visai supranta indeksus ir jų teikiamą naudą.
Dirbant su Ruby svetainėje Bėgiai sistemą, paprastai susiduriame su reliacinėmis duomenų bazėmis, pvz. "MySQL" arba "PostgreSQL". Apibrėždami perkėlimus naudojant "Active Record Migrations", susiduriame su vadinamaisiais indeksais, tačiau pradedantieji dažnai ne visai supranta indeksus ir jų teikiamą naudą.
Šiame įraše norėčiau paaiškinti, kas yra indeksai, kam jie naudojami, ir pateikti keletą gerosios praktikos pavyzdžių, kaip juos naudoti.
Duomenų bazė
Yra daug duomenų bazių variklių, o vieni populiariausių yra jau minėtos "MySQL", "PostgreSQL", "Oracle" arba "Microsoft SQL Server". Visos jos yra reliacinės duomenų bazės, o tai reiškia, kad visos duomenys yra susiję tarpusavyje ir saugomi lentelėse. Kiekviena lentelės eilutė vadinama įrašu ir turi savo unikalų identifikatorių (id). Populiariausių duomenų bazių variklių reitingą galite patikrinti adresu https://db-engines.com/en/ranking. Ten taip pat rasite keletą nereliatyvinių duomenų bazių, pavyzdžiui, MongoDB.
Indekso kūrimas
Mūsų duomenų bazių lentelėse gali būti nuo kelių iki kelių dešimčių, o kraštutiniais atvejais - iki kelių šimtų stulpelių. Nepamirškite, kad kiekviena lentelė gali turėti neribotą eilučių skaičių. Šis skaičius tiesiogiai neišplaukia iš duomenų bazės struktūros, todėl visada turėtume manyti, kad įrašų skaičius nuosekliai didės ir dėl to mūsų duomenų bazė augs. Pradinės prielaidos ir užklausos, parašytos esamose taikomosiose programose, gali būti puikios esant mažam ar vidutiniam įrašų skaičiui, tačiau laikui bėgant, kai gaunama daugiau duomenų, taikomosios programos ryšys su duomenų baze tampa nebeefektyvus.
Programuotojo vaidmuo - rašyti užklausas, kad iš lentelės ar lentelių būtų galima gauti tam tikrus duomenis, tačiau optimalus užklausos apdorojimo būdas priklauso nuo duomenų bazės variklio. Atminkite, kad duomenų bazių varikliai įkelia duomenis iš disko į atmintį ir tada juos nuskaito. Tai reiškia, kad jei vienu metu daug naudotojų atliks sudėtingas operacijas, keli iš jų turės laukti savo eilės, nes jų paieškoms įgyvendinti pritrūks išteklių. Štai kodėl labai svarbūs atitinkami indeksai.
Wiki: Indeksas - duomenų struktūra, kuri padidina paieškos operacijų su lentele atlikimo greitį.
Kiekvienam indeksui reikia apibrėžti raktus (vienam ar daugeliui stulpelių), pagal kuriuos bus ieškoma įrašų lentelėje. Duomenys indekse bus rūšiuojami pagal anksčiau apibrėžtą raktą, o tai gerokai pagreitins duomenų paiešką lentelėje. Paprasčiausias pavyzdys iš kasdienio gyvenimo yra telefonų knyga, kurioje žmonės surūšiuoti pagal vardą ir pavardę. Galima sakyti, kad šiuo atveju mūsų indeksas bus vardas ir pavardė.
Kaip pasirinkti geriausią indekso raktą? Tai nėra sunku - tereikia prisiminti kelias taisykles. Sukurkite indeksą pagal stulpelius, kurie:
- dažnai bus naudojami mūsų užklausose (KUR),
- kartu tarpusavyje duoda unikalią reikšmę (t. y. reikšmę, kuri nurodo lygiai vieną eilutę),
- bus naudojami kaip vadinamieji jungiamieji stulpeliai (JOIN),
- pateikti selektyviausius raktus, t. y. tuos, kurie užklausą rašant grąžina mažiausiai eilučių.
Jei jau žinome, kokie raktai bus optimalūs mūsų lentelei, taip pat galime paklausti savęs, kiek indeksų mums reikia. Šiuo atveju geriausia jau projektavimo etape žinoti užklausas, kurios bus susijusios su mūsų lentele.
Sukurkime indeksus konkrečioms užklausoms, kurios bus rodomos, bet nerašykime jų kiekvienam stulpeliui. Indeksus, kaip ir lenteles, reikia kažkur saugoti, todėl kurdami lenteles su indeksu kiekvienam stulpeliui, turime atsižvelgti į tai, kad naudojamos vietos kiekis gali gerokai padidėti.
Sukurti unikalų indeksą
Kitas klausimas, apie kurį turime galvoti, yra unikalumas. Verta skirti papildomas penkias minutes ir pagalvoti, ar mūsų indeksas tikrai unikalus. Taip užklausos optimizatoriui pasakysime, kad jis neturi tikėtis pasikartojimų užklausoje. Pavyzdžiui, el. pašto adresai:
frozenstringliteral: true
klasė CreateUsers < ActiveRecord::Migration[6.0]
def change
createtable :users do |t|
t.string :email, null: false
end
addindex :users, :email, unique: true
end
end
Pateiksiu "PostgreSQL" variklio pavyzdį ir parodysiu, kaip skiriasi el. pašto stulpelio su unikaliuoju indeksu ir be indekso užklausos greitis.
1. Galite naudoti pavyzdį kodas fragmentus savo duomenų bazėje, kad galėtumėte išbandyti toliau pateiktą pavyzdį. Pirmiausia sukurkime tuščią lentelę su vienu stulpeliu:
CREATE TABLE users (
email varchar
);
2. Testui sukurkime 10 000 įrašų:
DO $
BEGIN FOR i IN 1..10000 LOOP
INSERT INTO users values((select 'user' || i || '@example.com'));
END LOOP; END;
$;
Naudodami EXPLAIN ANALYZE patikrinsime, kaip greitai bus apdorota mūsų užklausa, kai duomenų bazėje norime rasti konkretų naudotoją.
EXPLAIN ANALYZE SELECT email FROM users WHERE email = 'user890example.com';
Mūsų užklausa privertė apeiti visą lentelę ieškant dominančio įrašo. mus.
Šis procesas vadinamas nuosekliuoju skenavimu. Šiuo atveju geriausiai tinka skaityti visą lentelę ir filtruoti tam tikras eilutes.
"PostgreSQL" išfiltruos nereikalingas eilutes ir grąžins tik tas, kurios mus domina. Šiuo atveju tai tikrai geriausia. Nuoseklusis nuskaitymas ne visada blogai, yra atvejų, kai nuoseklusis nuskaitymas yra idealus.
4. Dabar atėjo laikas patikrinti jau atliktą užklausą lentelėje, kurioje yra INDEX UNIQUE. Nustatykime indeksą ir atlikime užklausą.
Sukurti unikalią indekso indeksą index_email on users(email);
EXPLAIN ANALYZE SELECT email FROM users WHERE email = 'user890example.com';
Šį kartą "PostgreSQL" pasinaudojo indekso nuskaitymo galimybe, nes visi reikalingi stulpeliai jau yra indekse.
Naudojant rodyklę bus labai efektyvu pasirinkti tik kelias eilutes. Tačiau jei pasirenkama daugiau duomenų, indekso ir lentelės nuskaitymas užims per daug laiko.
Santrauka
Kaip matote, užklausos stulpeliui su indeksu vykdymo laikas yra daug trumpesnis (pateiktame pavyzdyje jis sumažėjo nuo 1,267 ms iki 0,111 ms, t. y. net 91,24%!). Svarbiausias skirtumas yra tai, kaip PostgreSQL ieško mus dominančio įrašo. Pirmuoju atveju duomenų bazės variklis mums reikalingo įrašo turėjo ieškoti visoje lentelėje. Tačiau antruoju atveju indekso struktūra yra surūšiuota ir unikali, todėl variklis žinojo, kur yra įrašas, o tai gerokai pagreitino užklausos apdorojimo laiką.
Didelių duomenų bazių ir labai sudėtingų užklausų atveju teisingai nustatyti indeksai gali gerokai pagreitinti jūsų programos darbą be būtinybės didinti kompiuterio, kuriuo atliekate paiešką duomenų bazėje, spartą.
Verta prisiminti, kad indeksų kūrimas kiekvienam stulpeliui nėra gera praktika. Sukurti indeksai pagreitins optimizatoriaus darbą ieškant dominančių duomenų, tačiau kartu sulėtins naujų duomenų įterpimą ir esamų atnaujinimą.