40-წუთიანი სამუშაო სესია რელაციურ მონაცემთა ბაზებზე — იმით დაწყებული, თუ რატომ ვმოდელირებთ მონაცემებს ცხრილებად, გავლით SQL-ზე, რომელსაც ყოველდღე წერთ, ტრანზაქციებსა და ACID-ზე, ინდექსებსა და შეკითხვის გეგმებზე, იმაზე, თუ რომელი ძრავა აირჩიოთ, და იმაზე, როგორ შექმნათ სქემა, რომელიც მოგვიანებით არ შეგებრძოლებათ.
კოდი მუდმივად იწერება თავიდან; მონაცემები კი ყველა მათგანს გადაურჩება. რელაციური მოდელი იმიტომ იმარჯვებს, რომ ერთ დაპირებას იძლევა, რომელსაც სხვა ვერავინ: თქვენი მონაცემების ერთი, სანდო ასლი, რომელსაც მრავალი პროგრამა ერთდროულად კითხულობს და წერს ერთმანეთისთვის ხელის შეშლის გარეშე. წარმოიდგინეთ ბანკის წიგნი — ყველა ოპერატორი და ბანკომატი ერთსა და იმავე ბალანსებს ეხება და არავის აქვს უფლება, ის ნახევრად განახლებული დატოვოს.
ბევრი პროგრამა, ერთი საერთო ჭეშმარიტება — მონაცემებს ფლობს ბაზა და არა რომელიმე ცალკეული აპი.
სქემა "გთხოვთ, ფრთხილად იყავით"-ს აქცევს წესებად, რომელთა დარღვევასაც ძრავა არ დაგანებებთ.
კარგი სქემა ყოველ ფაქტს ერთხელ ინახავს და ფაქტებს ერთმანეთს გასაღებებით უკავშირებს (გასაღები უბრალოდ სვეტია, რომლის საქმეც სტრიქონის იდენტიფიცირება ან მასზე მითითებაა). სწორად შერჩეული გასაღებებით მოდელი თავად აიხსნება — ხედავთ, როგორ უკავშირდება ყველაფერი ერთმანეთს უბრალოდ ცხრილების კითხვით, რადგან კავშირები მონაცემებში ცხოვრობს და არა მხოლოდ თქვენს თავში.
უნიკალური და არასოდეს null. აირჩიეთ სუროგატული გასაღები (ავტომატური id) და არა ბუნებრივი, როგორიცაა email — ბუნებრივი მნიშვნელობები იცვლება, id-ები კი არ უნდა იცვლებოდეს.
order.user_id → users.id. ძრავა უარყოფს შეკვეთას იმ მომხმარებლისთვის, რომელიც არ არსებობს — ობოლი სტრიქონები არ ჩნდება.
NOT NULL, UNIQUE, CHECK, DEFAULT — ინვარიანტები, რომლებიც ყველა მწერლისთვის მოქმედებს და არა მხოლოდ ფრთხილებისთვის.
orders.user_id).UNIQUE შეზღუდვა.ჰგავს ბიბლიოთეკას: ერთი მკითხველის ბარათი ბევრ გატანას უკავშირდება; თითოეული გატანა კი ერთ წიგნსა და ერთ მკითხველზე მიუთითებს.
order_items არის საკავშირო ცხრილი: ის შეკვეთები↔პროდუქტებს (მრავალი-მრავალთან) ორ სუფთა ერთი-მრავალთან კავშირად აქცევს.
SQL დეკლარაციულია: თქვენ აღწერთ სასურველ შედეგს და არა იმ ციკლებს, რომლებიც მას ააგებს. ოთხი კონსტრუქცია კითხვების აბსოლუტურ უმრავლესობას ფარავს — და ისინი ისეთი თანმიმდევრობით სრულდება, რომელიც ახალბედების უმეტესობას აოცებს.
SELECT კითხულობს სტრიქონებს; WHERE ფილტრავს მათ; JOIN აერთიანებს ცხრილებს გასაღებების დამთხვევით; GROUP BY კი ბევრ სტრიქონს ჯგუფების მიხედვით შეჯამებად კრავს.თქვენ წერთ SELECT … FROM … WHERE … GROUP BY …, მაგრამ ძრავა ჯერ FROM-ს ამუშავებს და SELECT-ს თითქმის ბოლოს. სწორედ ამიტომ ვერ გამოიყენებთ SELECT-ის ალიასს WHERE-ის შიგნით — ის ჯერ არ არსებობს.
ლოგიკური შეფასების თანმიმდევრობა — გაითავისეთ და დამაბნეველი შეცდომები აზრს შეიძენს.
WHERE-ს შესაბამისი სტრიქონები, დაალაგეთ და შემდეგ ერთ გვერდამდე შემოკვეცეთ.NULL არაფრის ტოლი არ არის — გამოიყენეთ IS NULL და არასოდეს = NULL.INNER = სტრიქონები, რომლებიც ორივეშია. LEFT = მარცხენას ყველა სტრიქონი, შევსებული NULL-ებით.ON join-ს დეკარტულ ნამრავლად აქცევს — სტრიქონების რაოდენობა აფეთქდება.WHERE ფილტრავს სტრიქონებს დაჯგუფებამდე; HAVING ფილტრავს ჯგუფებს დაჯგუფების შემდეგ.SELECT სვეტი GROUP BY-შიც უნდა იყოს.WITH ბლოკი დასახელებული, ადვილად წასაკითხი ქვეშეკითხვაა — დააჯაჭვეთ ისინი იმის ნაცვლად, რომ ხუთ დონეზე ჩალაგოთ.წაკითხვა მიმტევებელია; მონაცემები ჩაწერისას ფუჭდება. გამოსავალი ტრანზაქციაა — საზღვარი, რომელიც ამბობს: "ან ყველა მათგანი წარმატდება, ან არცერთი". ACID არის ის ოთხი გარანტია, რომელსაც ის გაძლევთ.
BEGIN … COMMIT-ში; თუ რამე ჩავარდება, ROLLBACK მთელ პარტიას ისე გააუქმებს, თითქოს ის არასოდეს შესრულებულა.ატომურობა ერთ სურათში: ტრანზაქცია ან მთლიანად ჯდება, ან მთლიანად ქრება.
როცა ტრანზაქციები ერთდროულად სრულდება, იზოლაციის დონე წყვეტს, თითოეულმა მათგანმა სხვების მიმდინარე სამუშაოდან რა დაინახოს. უფრო თავისუფალი = უფრო სწრაფი, მაგრამ ანომალიებს უშვებს; უფრო მკაცრი = უფრო უსაფრთხო, მაგრამ მეტი კონკურენციით.
ჰგავს საერთო დოკუმენტის რედაქტირებას: იზოლაცია განსაზღვრავს, სხვისი ნახევრად დასრულებული ცვლილებიდან რამდენის დანახვის უფლება გაქვთ.
ძრავა თქვენს SQL-ს პირდაპირ არ ასრულებს — ის შეკითხვის გეგმას აგებს. წარმადობაზე მუშაობის უდიდესი ნაწილი ამ გეგმის წაკითხვა და მისთვის უფრო სწრაფი გზის მიცემაა. ყველაზე დიდი ბერკეტი ინდექსია.
O(n) სკანირებას O(log n) ძებნად აქცევს.WHERE, JOIN და ORDER BY გაქვთ — და არა ყველა სვეტი.მარცხნივ: ძრავა ყველაფერს კითხულობს. მარჯვნივ: B-ხე რამდენიმე კვანძს გაივლის პირდაპირ დამთხვევამდე.
INSERT/UPDATE.(user_id, placed_at) ეხმარება მხოლოდ user_id-ზე ფილტრს, მაგრამ არა მხოლოდ placed_at-ზე.EXPLAIN-ით და ნუ გამოიცნობთ.ნაგულისხმევად ნორმალიზება: ერთი ფაქტი, ერთი ადგილი, წინააღმდეგობების გარეშე. დენორმალიზება კი შეგნებულად — და მხოლოდ მაშინ, როცა გაზომილი წაკითხვის პრობლემა ამართლებს იმ დუბლირებას, რომელსაც იღებთ.
ტრანზაქციული სისტემები — შეკვეთები, ანგარიშები, მარაგები. სისწორე და იაფი განახლებები სჯობს წაკითხვის სუფთა სიჩქარეს. ეს ნაგულისხმევი არჩევანია.
ცხელი შეკითხვა ხუთ ცხრილს აერთებს ყოველი გვერდის ჩატვირთვისას. წინასწარ გამოთვალეთ ან დააქეშირეთ ეს ფორმა — მას შემდეგ, რაც დაამტკიცებთ, რომ join არის ბოთლის ყელი.
ყოველი დუბლირებული მნიშვნელობა მომავალი ბაგია, რომელიც ელოდება, რომ განახლება ერთ ასლს გამოტოვებს. დენორმალიზაცია ჩაწერის ტკივილს წაკითხვის სიჩქარეზე ცვლის — არასოდეს უფასოდ.
პრაქტიკული წესი: ანორმალიზეთ, სანამ არ ატკივდება, შემდეგ კი დენორმალიზეთ, სანამ არ იმუშავებს — ციფრებით და არა შეგრძნებით.
აქამდე თითქმის ყველაფერი ვენდორ-ნეიტრალური იყო — ის ერთნაირად მუშაობს პოპულარულ მონაცემთა ბაზებში. მთავარი გზაგასაყარია რელაციური თუ დოკუმენტური: მონაცემებს დაკავშირებულ ცხრილებად ჰყოფთ თუ ყოველ ჩანაწერს ერთ თვითკმარ ბლობად ინახავთ? აი წამყვანი ძრავები, თითოეულის ძლიერი და სუსტი მხარეები და არჩევის წესი.
users-ში ცხოვრობს; მისი შეკვეთები orders-ში და გასაღებით უკან მიუთითებს. არაფერი დუბლირდება და join მათ ერთმანეთს აკერებს, როცა დაგჭირდებათ.მარცხნივ: ფაქტები ერთხელ ინახება და გასაღებით უკავშირდება. მარჯვნივ: იგივე ფაქტები ერთ დოკუმენტშია ჩალაგებული.
დადებითი — უკიდურესად მდიდარი ფუნქციონალით და მკაცრი სისწორის მიმართ; JSON-ს, სრულტექსტურ ძებნას და სხვას დანამატების გარეშე უმკლავდება.
უარყოფითი — მეტი ფუნქციონალი მეტ სასწავლს ნიშნავს, ხოლო ყუთიდან ამოღებული პარამეტრები ფრთხილადაა აწყობილი.
დადებითი — მუშაობს პრაქტიკულად ყველა ჰოსტზე, ადვილად დასაწყებია და სწრაფია მარტივი, წაკითხვაზე ორიენტირებული საიტებისთვის.
უარყოფითი — ისტორიულად უფრო თავისუფალია სისწორეში და PostgreSQL-ზე ღარიბი ფუნქციონალი აქვს.
დადებითი — ინახავს ჩალაგებულ, JSON-ის ფორმის ჩანაწერებს ფიქსირებული სქემის გარეშე; სწრაფად საწყებია, სანამ მონაცემები ფორმას ჯერ კიდევ იცვლის.
უარყოფითი — რეალური join-ები არ არსებობს და ძრავა თქვენს კავშირებს არ იცავს, ამიტომ თანმიმდევრულობა ახლა თქვენს აპს ეკისრება.
დადებითი — ნულოვანი დაყენება, პირდაპირ თქვენს აპში მუშაობს და იდეალურია ლოკალური აპებისთვის, პროტოტიპებისა და ტესტებისთვის.
უარყოფითი — ერთდროულად მხოლოდ ერთი მწერალი, ამიტომ დატვირთული მრავალმომხმარებლიანი სერვერისთვის ეს არასწორი ინსტრუმენტია.
როგორ ავირჩიოთ: მიმართეთ PostgreSQL-ს თითქმის ყველა აპისთვის, სადაც რეალური კავშირებია; აირჩიეთ MySQL, თუ თქვენი პლატფორმა უკვე მასზეა სტანდარტიზებული; აირჩიეთ MongoDB მხოლოდ მაშინ, როცა მონაცემები ნამდვილად დოკუმენტის ფორმისაა და იშვიათად ერთდება; ხოლო SQLite გამოიყენეთ ლოკალური აპებისთვის, პროტოტიპებისა და ტესტების ნაკრებისთვის.
სტრიქონული საცავი ჩანაწერს ერთად ინახავს (შესანიშნავია "მომეცი ეს შეკვეთა"-სთვის); სვეტური საცავი თითოეულ ველს ინახავს ერთად, ამიტომ აგრეგატი მხოლოდ საჭირო სვეტს კითხულობს.
პრაქტიკული წესი: OLTP (Postgres / MySQL) აპს ამუშავებს; OLAP (ClickHouse ან საწყობი) კი მასზე კითხვებს პასუხობს. გუნდები ხშირად ორივეს უშვებენ — საწყობს აპის ბაზიდან კვებავენ (ეს უკვე ETL/ELT დეკია).
შევკრათ ერთად: აიღეთ ბრტყელი "ყველაფერი ერთ ცხრილში" დიზაინი და აქციეთ ის გასაღებებად, კავშირებად და შეზღუდვებად — შემდეგ კი წესებით ხელში გახვიდეთ.
NOT NULL, CHECK — ძრავაში და არა მხოლოდ აპში.EXPLAIN; შემდეგ დააინდექსეთ ის სვეტები, რომლებზეც ფილტრავთ და აერთებთ.EXPLAIN-ზე — Postgres-საც და MySQL-საც შესანიშნავი აქვთ"დაამოდელირეთ ჭეშმარიტება ერთხელ, დაცვა ძრავას მიანდეთ და კითხვები SQL-ით დაუსვით."
— მთელი მოხსენება, შეკუმშული
ხუთი სწრაფი კითხვა სქემის დიზაინზე, SQL-ზე, ტრანზაქციებსა და ინდექსებზე — მყისიერი უკუკავშირი, ავტორიზაციის გარეშე.
ნავიგაცია ← → ისრებით ან სქროლით · ნაწილი 2: გაღრმავებული SQL → · უკან ბიბლიოთეკაში