Ruby on Rails programmatūras izstrāde. Rādītāji v2
Damians Watroba
Software Engineer
Strādājot ar Ruby on Rails ietvaru, mēs parasti strādājam ar relāciju datubāzēm, piemēram, MySQL vai PostgreSQL. Definējot migrāciju, izmantojot Active Record Migrations, mēs saskaramies ar tā sauktajiem indeksiem, taču iesācēji bieži vien īsti neizprot indeksus un to priekšrocības.
Strādājot ar Rubīns vietnē Sliedes sistēmu, mēs parasti strādājam ar relāciju datu bāzēm, piemēram. MySQL vai PostgreSQL. Definējot migrāciju, izmantojot Active Record Migrations, mēs saskaramies ar tā sauktajiem indeksiem, taču iesācēji bieži vien īsti neizprot indeksus un to priekšrocības.
Šajā rakstā vēlos izskaidrot, kas ir indeksi, kādiem nolūkiem tos izmanto, un iepazīstināt ar dažiem labiem piemēriem, kā tos izmantot.
Datubāze
Ir daudz datu bāzu datubāzu dzinēju, un vieni no populārākajiem ir iepriekš minētie MySQL, PostgreSQL, Oracle vai Microsoft SQL Server. Tās visas ir relāciju datubāzes, kas nozīmē, ka visas dati ir savstarpēji saistīti un glabājas tabulās. Katru tabulas rindu sauc par ierakstu, un katrai ir savs unikāls identifikators (id). Populārāko datubāzu dzinēju rangu var pārbaudīt vietnē https://db-engines.com/en/ranking. Tur atradīsiet arī dažas nerelatīvās datubāzes, piemēram, MongoDB.
Indeksa izveide
Mūsu datubāzu tabulās var būt no dažiem līdz pat vairākiem desmitiem, bet galējos gadījumos - līdz pat vairākiem simtiem kolonnu. Paturiet prātā, ka katrā tabulā var būt neierobežots rindu skaits. Šis skaits neizriet tieši no datubāzes struktūras, un mums vienmēr jāpieņem, ka ierakstu skaits secīgi palielināsies un līdz ar to mūsu datubāze palielināsies. Sākotnējie pieņēmumi un esošajās lietojumprogrammās rakstītie pieprasījumi var būt lieliski nelielam vai vidējam ierakstu skaitam, bet laika gaitā, kad datu kļūst vairāk, lietojumprogrammas saziņa ar datubāzi vairs nav efektīva.
Programmētāja uzdevums ir rakstīt vaicājumus, lai iegūtu datus no tabulas vai tabulām, bet optimālais vaicājuma apstrādes veids ir atkarīgs no datubāzes dzinēja. Atcerieties, ka datubāzu dzinēji ielādē datus no diska atmiņā un pēc tam tos skenē. Tas nozīmē, ka, ja daudzi lietotāji vienlaicīgi veic sarežģītas operācijas, vairākiem no viņiem nāksies gaidīt savu kārtu, jo trūks resursu, lai īstenotu meklēšanu. Tāpēc ir tik svarīgi attiecīgie indeksi.
Wiki: Rādītājs - datu struktūra, kas palielina meklēšanas operāciju veikšanas ātrumu tabulā.
Katram indeksam ir jādefinē atslēgas (vienam vai vairākiem stabiņiem), kas tiks izmantotas ierakstu meklēšanai tabulā. Dati indeksā tiks sakārtoti pēc iepriekš definētās atslēgas, kas ievērojami paātrinās datu meklēšanu tabulā. Vienkāršākais piemērs no ikdienas dzīves ir tālruņu grāmata, kurā cilvēki ir sakārtoti pēc vārda un uzvārda. Var teikt, ka mūsu indekss šajā gadījumā būs vārds un uzvārds.
Kā izvēlēties labāko indeksa atslēgu? Tas nav sarežģīti - tikai atcerieties dažus noteikumus. Izveidojiet indeksu, pamatojoties uz kolonnām, kas:
- bieži tiks izmantoti mūsu pieprasījumos (KUR),
- kombinācijā kopā veido unikālu vērtību (t. i., vērtību, kas norāda tieši vienu rindu),
- tiks izmantoti kā tā sauktie savienojošie kolonnas (JOIN),
- sniedz visselektīvāk atlasītos atslēgas taustiņus, t. i., atslēgas, kas, rakstot vaicājumu, atgriež vismazāko rindu skaitu.
Ja jau zinām, kuri atslēgas taustiņi būs optimāli mūsu tabulai, varam arī uzdot sev jautājumu par to, cik indeksu mums ir nepieciešams. Šajā gadījumā vislabāk jau projektēšanas posmā zināt, kādi pieprasījumi attieksies uz mūsu tabulu.
Izveidosim indeksus konkrētiem pieprasījumiem, kas tiks parādīti, bet nerakstīsim tos katrai kolonnai. Indeksus, tāpat kā tabulas, ir nepieciešams kaut kur glabāt, tāpēc, veidojot tabulas ar indeksu katrai kolonnai, jāņem vērā, ka izmantotās vietas apjoms var ievērojami palielināties.
Izveidot unikālu indeksu
Vēl viens jautājums, par ko mums ir jādomā, ir unikalitāte. Ir vērts veltīt papildu piecas minūtes, lai padomātu, vai mūsu indekss patiešām ir unikāls. Šādā veidā mēs sakām vaicājuma optimizatoram, ka tam nav jāgaida, ka pieprasījumā būs dublēšanās. Piemēram, e-pasta adreses:
frozenstringliteral: true
klase CreateUsers < ActiveRecord::Migration[6.0]
def change
createtable :users do |t|
t.string :email, null: false
end
addindex :users, :email, unique: true
end
end
Izmantojot PostgreSQL dzinēja piemēru, es parādīšu atšķirību starp e-pasta slejas ar unikālu indeksu un bez indeksa meklēšanas ātrumu.
1. Jūs varat izmantot paraugu kods fragmentus savā datubāzē, lai varētu pārbaudīt tālāk sniegto piemēru. Vispirms izveidosim tukšu tabulu ar vienu kolonnu:
CREATE TABLE users (
email varchar
);
2. Izveidosim 10 000 ierakstu testam:
DO $
BEGIN FOR i IN 1..10000 LOOP
INSERT INTO users values((select 'user' || i || '@example.com'));
END LOOP; END;
$;
Mēs izmantosim EXPLAIN ANALYZE, lai pārbaudītu, cik ātri tiks apstrādāts mūsu vaicājums, ja vēlamies datubāzē atrast konkrētu lietotāju.
EXPLAIN ANALYZE SELECT email FROM users WHERE email = 'user890example.com';
Mūsu vaicājums piespiedu kārtā iterē visu tabulu, meklējot ierakstu, kas interesē. mums.
Šo procesu sauc par secīgu skenēšanu. Šajā gadījumā vislabākais veids, kā veikt šo uzdevumu, ir visas tabulas nolasīšana un konkrētu rindu filtrēšana.
PostgreSQL izfiltrēs nevajadzīgās rindas un atgriezīs tikai tās, kas mūs interesē. Šajā gadījumā tas patiešām ir labākais risinājums. Secīgā skenēšana ne vienmēr ir slikta, ir gadījumi, kad secīgā skenēšana ir ideāla.
4. Tagad ir laiks pārbaudīt jau veikto vaicājumu par tabulu, kurai ir INDEX UNIQUE. Iestatīsim indeksu un izpildīsim vaicājumu.
Izveidot unikālo indeksa indeksu index_email uz users(email);
EXPLAIN ANALYZE SELECT email FROM users WHERE email = 'user890example.com';
Šoreiz PostgreSQL izmantoja indeksa skenēšanu, jo visi nepieciešamie kolonnas jau ir indeksā.
Izmantojot indeksu, ļoti efektīvi var atlasīt tikai dažas rindas. Tomēr, ja tiek atlasīts vairāk datu, indeksa un tabulas skenēšana būs pārāk laikietilpīga.
Kopsavilkums
Kā redzams, vaicājuma izpildes laiks slejā ar indeksu ir daudz īsāks (attēlotajā piemērā tas ir samazinājums no 1,267 ms līdz 0,111 ms, t.i., līdz pat 91,24%!). Svarīgākā atšķirība ir veids, kādā PostgreSQL meklē mūs interesējošo ierakstu. Pirmajā gadījumā datubāzes dzinējam vajadzēja meklēt mums vajadzīgo ierakstu visā tabulā. Savukārt otrajā gadījumā indeksa struktūra ir sakārtota un unikāla, tāpēc dzinējs zināja, kur atrodas attiecīgais ieraksts, un tas ievērojami paātrināja pieprasījuma apstrādes laiku.
Lielu datubāzu un ļoti sarežģītu vaicājumu gadījumā pareizi iestatīti indeksi var ievērojami paātrināt jūsu lietojumprogrammas darbu, nepalielinot mašīnas, kurā meklējat datubāzē, ātrumu.
Ir vērts atcerēties, ka indeksu izveide katrai kolonnai nav laba prakse. Izveidoti indeksi paātrinās optimizatora darbu, meklējot interesējošos datus, bet vienlaikus palēninās jaunu datu ievietošanu un esošo datu atjaunināšanu.