Når databasens størrelse vokser til over millioner af rækker, er det tilrådeligt at begynde at skalere programmet og opdele databasen på flere fysiske servere.
Det største problem ved at opdele en database i flere dele er den efterfølgende synkronisering, når en bruger anmoder om specifikke data.
Lad os antage, at du har en tabel med articles
, men fordi du har et stort websted, er der flere millioner artikler, og du er nødt til fysisk at dele dem op på flere maskiner.
Hvis vi skulle bruge et almindeligt heltal som id
(primærnøgle) med indstillingen autoincrement, ville vi meget hurtigt opdage, at når vi opretter poster på forskellige maskiner på en decentraliseret måde og derefter synkroniserer dem, opstår der ID-kollisioner, og vi er nødt til at omnummerere posterne på en kompliceret måde. Hvis vi desuden løser mange sessioner til andre tabeller, kan dette være et meget komplekst overhead, hvor det er let at begå fejl.
Derfor kan vi i stedet for en numerisk identifikator generere et UUID
, som er en tekststreng, der genereres af en kompleks algoritme, der garanterer, at den vil være unik, selv om den genereres uafhængigt af hinanden på flere maskiner.
Fordele:
primary key
før du faktisk indsætter posten i databasen. Dette reducerer antallet af SQL-forespørgsler, forenkler transaktionslogikken, og du kan nemt bruge den som en fremmednøgle, før record collection eksisterer.19010018
, er det let at gætte, at der også findes brugeren 19010017
og andre. Dette angreb kaldes et vektorangreb.UUID kan fås enten ved en simpel SQL-forespørgsel SELECT UUID();
, men dette øger antallet af forespørgsler til databasen, og vi mister muligheden for at forberede dataene først i bulk i applikationslogikken og derefter skrive dem på én gang.
Derfor kan jeg godt lide at bruge ramsey/uuid-pakken, som fås af Composer, som en god løsning. Selve UUID'et har flere versioner, og pakken kan legevis generere alle slags versioner efter behov.
Det gør det nemt at bruge:
require 'vendor/autoload.php';use Ramsey\Uuid\Uuid;// Genererer UUID-objekt i version 1 (tidsbaseret)$uuid1 = Uuid::uuid1();echo $uuid1->toString() . "\n"; // e4eaaaf2-d142-11e1-b3e4-080027620cdd// Genererer UUID-objekt i version 3 (navnebaseret og hashed som MD5)$uuid3 = Uuid::uuid3(Uuid::NAMESPACE_DNS, 'php.net');echo $uuid3->toString() . "\n"; // 11a38b9a-b3da-360f-9353-a5a725514269// Genererer UUID-objekt i version 4 (tilfældigt)$uuid4 = Uuid::uuid4();echo $uuid4->toString() . "\n"; // 25769c6c-d34d-4bfe-ba98-e0ee856f3e7a// Genererer UUID-objekt i version 5 (navnebaseret og hashed som SHA1)$uuid5 = Uuid::uuid5(Uuid::NAMESPACE_DNS, 'php.net');echo $uuid5->toString() . "\n"; // c4a760a8-dbcf-5254-a0d9-6a4474bd1b62
Hvis du bruger Doctrine, er der en udvidelse ramsey/uuid-doctrine, der genererer ID'et direkte som en datatype.
I mine første forsøg brugte jeg varchar(36)
som primærnøgle (ID), men det er slet ikke en god idé.
Oplysning af den interne logik:
MySql-databaser (og mange andre) kan ikke bruge
varchar
,char
eller andre datatyper, der udtrykker en streng som primærnøgle, effektivt. I nogle databaser findes der en datatypeGUID
, som er designet til at gemme UUID'er direkte. Hvis du ikke kan bruge denne type, findes der en passende erstatning i form afbinary(16)
.
Når databasen undersøges fysisk, repræsenteres ID'et i HEX-format (da binært format ikke kan vises), og i stedet for det flotte ID 726c67c4-e5eb-4a4c-8fcc-031da5d6f3c6
, vil du blot se 726C67C67C4E5EB4A4C8FCC031DA5D6F3C6
, som ligner '?kYߟKg2c;'
i INSERT-forespørgslen.
varchar(36)
til binary(16)
Jeg går ud fra, at du repræsenterer (eller planlægger at repræsentere) det nyligt indstillede ID i databasen som:
`id` binary(16) NOT NULL
Det virker dog ikke at ændre datatypen, så noget som:
SET FOREIGN_KEY_CHECKS=0;ALTER TABLE article CHANGE id id BINARY(16) NOT NULLSET FOREIGN_KEY_CHECKS=1;
Der er grundlæggende to grunde:
Derfor er den eneste rigtige løsning at tage backup af dataene (men det bør du alligevel gøre før hver migrering), forberede en tom database med funktionelle relationer og lægge dataene der igen via migrering.
Hvis du tidligere har genereret UUID'er på en mærkelig måde, er det bedre at vælge en sekventiel metode til at få UUID'et og omnummerere alle poster. Årsagen er, at sekventielt layout giver bedre mulighed for at ordne værdierne og skabe et btree
, hvilket gør ydelsen næsten identisk med bigint
.
Hvis du kender en bedre måde at konvertere en eksisterende database fra UUID gemt som varchar til binært format uden at skulle udarbejde komplekse migreringer og med bevarelse af fremmednøgler, vil jeg være meget taknemmelig for feedback.
Jan Barášek Více o autorovi
Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.
Rád vám pomůžu:
Články píše Jan Barášek © 2009-2024 | Kontakt | Mapa webu
Status | Aktualizováno: ... | da