När databasens storlek överstiger miljontals rader är det lämpligt att börja skala programmet och dela upp databasen på flera fysiska servrar.
Det största problemet med att dela upp databasen i flera delar är den efterföljande synkroniseringen om användaren begär specifika uppgifter.
Anta att du har en tabell med articles
, men eftersom du har en stor webbplats finns det tiotals miljoner artiklar högre upp och du måste fysiskt dela upp dem på flera maskiner.
Om vi skulle använda ett vanligt heltal som id
(primärnyckel) med inställningen autoincrement, skulle vi mycket snabbt upptäcka att när vi skapar poster på olika maskiner på ett decentraliserat sätt och sedan synkroniserar dem, uppstår ID-kollisioner och vi måste numrera om posterna på ett komplicerat sätt. Om vi dessutom löser upp många sessioner till andra tabeller kan detta bli en mycket komplex overhead där det är lätt att göra misstag.
I stället för en numerisk identifierare kan vi därför generera en UUID
, som är en textsträng som genereras av en komplex algoritm som garanterar att den är unik även om den genereras oberoende av varandra på flera maskiner.
Fördelar:
19010018
är det lätt att gissa att det också finns användare 19010017
och andra. Attacken kallas en vektorattack.UUID kan erhållas antingen genom en enkel SQL-fråga SELECT UUID();
, men detta ökar antalet frågor till databasen och vi förlorar möjligheten att förbereda data först i bulk i programlogiken och sedan skriva dem på en gång.
Därför gillar jag att använda paketet ramsey/uuid som Composer har fått fram som en bra lösning. Själva UUID har flera versioner, och paketet kan på ett lekfullt sätt generera alla sorters versioner efter behov.
Det gör den lätt att använda:
require 'säljare/autoload.php';use Ramsey\Uuid\Uuid;// Genererar UUID-objekt i version 1 (tidsbaserat)$uuid1 = Uuid::uuid1();echo $uuid1->toString() . "\n"; // e4eaaaf2-d142-11e1-b3e4-080027620cdd// Genererar UUID-objekt i version 3 (namnbaserat och hashed som MD5).$uuid3 = Uuid::uuid3(Uuid::NAMESPACE_DNS, 'php.net');echo $uuid3->toString() . "\n"; // 11a38b9a-b3da-360f-9353-a5a725514269// Genererar UUID-objekt i version 4 (slumpmässigt)$uuid4 = Uuid::uuid4();echo $uuid4->toString() . "\n"; // 25769c6c-d34d-4bfe-ba98-e0ee856f3e7a// Genererar UUID-objekt av version 5 (namnbaserat och hashed som SHA1).$uuid5 = Uuid::uuid5(Uuid::NAMESPACE_DNS, 'php.net');echo $uuid5->toString() . "\n"; // c4a760a8-dbcf-5254-a0d9-6a4474bd1b62
Om du använder Doctrine finns det ett tillägg ramsey/uuid-doctrine som genererar ID direkt som en datatyp.
I mina första försök använde jag varchar(36)
som primärnyckel (ID), men det är inte alls en bra idé.
förklaring av den interna logiken:
MySql-databaser (och många andra) kan inte använda
varchar
,char
eller andra datatyper som uttrycker en sträng som primärnyckel på ett effektivt sätt. I vissa databaser finns det en datatypGUID
som är utformad för att lagra UUID:er direkt. Om du inte kan använda den här typen finns det en lämplig ersättning i form avbinary(16)
.
När du undersöker databasen fysiskt representeras ID:t i HEX-format (eftersom binärt format inte kan visas), istället för det fina ID:t 726c67c4-e5eb-4a4c-8fcc-031da5d6f3c6
, kommer du bara att se 726C67C4E5EB4A4C8FCC031DA5D6F3C6
, vilket ser ut som '?kYߟKg2c;'
i INSERT-frågan.
varchar(36)
till binary(16)
.Jag antar att du representerar (eller planerar att representera) det nyligen fastställda ID:t i databasen som:
`id` binary(16) NOT NULL
Att bara ändra datatypen fungerar dock inte, så något som:
SET FOREIGN_KEY_CHECKS=0;ALTER TABLE article CHANGE id id BINARY(16) NOT NULLSET FOREIGN_KEY_CHECKS=1;
Det finns i princip två skäl:
Därför är den enda korrekta lösningen att säkerhetskopiera data (men det bör du göra före varje migrering ändå), förbereda en tom databas med funktionella relationer och lägga in data där igen via migrering.
Om du har genererat UUID:er på ett konstigt sätt tidigare är det bättre att välja en sekventiell metod för att få fram UUID:n och numrera om alla poster. Anledningen är att sekventiell layout gör det möjligt att ordna värdena bättre och skapa ett btree
, vilket gör att prestandan är nästan identisk med bigint
.
Om du känner till ett bättre sätt att konvertera en befintlig databas från UUID lagrad som varchar till binärt format utan att behöva göra komplexa migreringar och med bevarade utländska nycklar, skulle jag vara mycket tacksam för 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: ... | sv