sql >> Databasteknik >  >> RDS >> Mysql

Skapa ett index på en enorm MySQL-produktionstabell utan tabelllåsning

[2017] Uppdatering:MySQL 5.6 har stöd för onlineindexuppdateringar

https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-operations.html#online-ddl-index-syntax-notes

I MySQL 5.6 och högre förblir tabellen tillgänglig för läs- och skrivoperationer medan indexet skapas eller tas bort. CREATE INDEX- eller DROP INDEX-satsen avslutas först efter att alla transaktioner som kommer åt tabellen har slutförts, så att indexets initiala tillstånd återspeglar det senaste innehållet i tabellen. Tidigare har modifiering av tabellen medan ett index skapas eller tas bort vanligtvis resulterat i ett dödläge som avbröt INSERT-, UPDATE- eller DELETE-satsen i tabellen.

[2015] Uppdatering av tabellindex blockerar skriver i MySQL 5.5

Från svaret ovan:

"Om du använder en version som är större än 5.1 skapas index medan databasen är online. Så oroa dig inte, du kommer inte att avbryta användningen av produktionssystemet."

Detta är ****FALSK**** (åtminstone för MyISAM / InnoDB-tabeller, vilket är vad 99,999 % av människorna där ute använder. Clustered Edition är annorlunda.)

Om du gör UPPDATERING på ett bord kommer att BLOCKAS medan indexet skapas. MySQL är riktigt, riktigt dumt om detta (och några andra saker).

Testskript:

(   
  for n in {1..50}; do
    #(time mysql -uroot -e 'select  * from website_development.users where id = 41225\G'>/dev/null) 2>&1 | grep real;
    (time mysql -uroot -e 'update website_development.users set bio="" where id = 41225\G'>/dev/null) 2>&1 | grep real;
  done
) | cat -n &
PID=$!
sleep 0.05
echo "Index Update - START"
mysql -uroot website_development -e 'alter table users add index ddopsonfu (last_name, email, first_name, confirmation_token, current_sign_in_ip);'
echo "Index Update - FINISH"
sleep 0.05
kill $PID
time mysql -uroot website_development -e 'drop index ddopsonfu on users;'

Min server (InnoDB):

Server version: 5.5.25a Source distribution

Utdata (lägg märke till hur den sjätte operationen blockerar under de ~400 ms som det tar att slutföra indexuppdateringen):

 1  real    0m0.009s
 2  real    0m0.009s
 3  real    0m0.009s
 4  real    0m0.012s
 5  real    0m0.009s
Index Update - START
Index Update - FINISH
 6  real    0m0.388s
 7  real    0m0.009s
 8  real    0m0.009s
 9  real    0m0.009s
10  real    0m0.009s
11  real    0m0.009s

Vs läsoperationer som inte blockerar (byt radkommentaren i skriptet):

 1  real    0m0.010s
 2  real    0m0.009s
 3  real    0m0.009s
 4  real    0m0.010s
 5  real    0m0.009s
Index Update - START
 6  real    0m0.010s
 7  real    0m0.010s
 8  real    0m0.011s
 9  real    0m0.010s
...
41  real    0m0.009s
42  real    0m0.010s
43  real    0m0.009s
Index Update - FINISH
44  real    0m0.012s
45  real    0m0.009s
46  real    0m0.009s
47  real    0m0.010s
48  real    0m0.009s

Uppdatering av MySQL:s schema utan driftstopp

Hittills finns det bara en metod jag känner till för att uppdatera ett MySql-schema och inte drabbas av ett tillgänglighetsavbrott. Cirkulära mästare:

  • Master A har din MySQL-databas som körs på den
  • Ta i bruk Master B och låt den replikera skrivningar från Master A (B är en slav av A)
  • Utför schemauppdateringen på Master B. Det kommer att hamna på efterkälken under uppgraderingen
  • Låt mästare B komma ikapp. Invariant:Din schemaändring MÅSTE kunna bearbeta kommandon som replikeras från ett nedversionsschema. Indexeringsändringar kvalificerar sig. Enkla kolumntillägg kvalificerar vanligtvis. Ta bort en kolumn? antagligen inte.
  • BYTA ATOMISKT alla klienter från Master A till Master B. Om du vill vara säker (tro mig, det gör du), bör du se till att den sista skrivningen till A replikeras till B INNAN B tar sin första skrivning. Om du tillåter samtidiga skrivningar till 2+ masters, ... förstår du bättre MySQL-replikering på en DEEP-nivå eller så är du på väg mot en värld av smärta. Extrem smärta. Som, har du en kolumn som är AUTOINCREMENT??? du är skruvad (om du inte använder jämna nummer på en master och odds på den andra). Lita INTE på att MySQL-replikering "gör rätt sak". Det är INTE smart och kommer inte att rädda dig. Det är bara något mindre säkert än att kopiera binära transaktionsloggar från kommandoraden och spela upp dem för hand. Att koppla bort alla klienter från den gamla mastern och vända dem till den nya mastern kan ändå göras på några sekunder, mycket snabbare än att vänta på en flertimmars schemauppgradering.
  • Nu är Master B din nya mästare. Du har det nya schemat. Livet är gott. Ta en öl; det värsta är över.
  • Upprepa processen med Master A, uppgradera hans schema så att han blir din nya sekundära master, redo att ta över i händelse av att din primära master (master B nu) tappar makten eller bara går upp och dör på dig.

Det här är inte ett enkelt sätt att uppdatera schemat. Fungerar i en seriös produktionsmiljö; Ja det är det. Snälla, snälla, snälla, om det finns ett enklare sätt att lägga till ett index till en MySQL-tabell utan att blockera skrivningar, låt mig veta.

Googling ledde mig till denna artikel som beskriver en liknande teknik. Ännu bättre, de rekommenderar att man dricker vid samma tidpunkt i proceduren (Observera att jag skrev mitt svar innan jag läste artikeln)!

Perconas pt-online-schema-change

artikeln Jag länkade ovan talar om ett verktyg, pt -online-schema-change , som fungerar enligt följande:

  • Skapa en ny tabell med samma struktur som originalet.
  • Uppdatera schema för ny tabell.
  • Lägg till en utlösare på den ursprungliga tabellen så att ändringarna hålls synkroniserade med kopian
  • Kopiera rader i omgångar från den ursprungliga tabellen.
  • Flytta den ursprungliga tabellen ur vägen och ersätt den med en ny tabell.
  • Släpp gammal tabell.

Jag har aldrig provat verktyget själv. YMMV

RDS

Jag använder för närvarande MySQL genom Amazon's RDS . Det är en riktigt snygg tjänst som avslutar och hanterar MySQL, som låter dig lägga till nya läsrepliker med en enda knapp och transparent uppgradera databasen över hårdvaru-SKU:er. Det är riktigt bekvämt. Du får inte SUPER tillgång till databasen, så du kan inte skruva med replikering direkt (är detta en välsignelse eller förbannelse?). Du kan dock använda Läs Replica Promotion för att göra dina schemaändringar på en skrivskyddad slav, främja sedan den slaven att bli din nya mästare. Exakt samma knep som jag beskrev ovan, bara mycket lättare att utföra. De gör fortfarande inte mycket för att hjälpa dig med cut-over. Du måste konfigurera om och starta om din app.



  1. Hur man sammanfogar strängar i SQL

  2. Generera dynamiskt kolumner för korstabell i PostgreSQL

  3. MySQL CEILING() Funktion – Runda uppåt till närmaste heltal

  4. Konfiguration med hög tillgänglighet för ClusterControl-noder med CMON HA