SlideShare a Scribd company logo
1 of 55
Download to read offline
MySQL
Validate Your Schema and
change it smoothly
9 kwiecień 2018
4developers
Piotr Suszalski
agenda
● Big Picture
W jakiej kondycji jest moja baza danych?
Gdzie szukać potencjalnych problemów?
● Odpowiednio zaprojektowana struktura
Jak projektować tabele?
Jakich typów danych używać?
● Zmiany struktury bazy
Jak zmienić strukturę danych w dużych tabelach (np 300GB)?
2
Big picture
3 3
od czego zacząć?
● MySQL internals
● information_schema
● Percona Toolkit
● pt-duplicate-key-checker
● pt-mysql-summary
4
information_schema
● Baza danych
● Zawiera widoki (readonly)
● Zapewnia dostęp do metadanych o:
● tabelach
● kolumnach
● indeksach
● triggerach
● widokach
● itp.
● Można wykonywać na niej standardowe SQLki
5
information_schema - overview
SELECT engine,
row_format,
table_name,
concat(round(table_rows/1000000,2),'M') rows,
concat(round(data_length/(1024*1024*1024),2),'G') data,
concat(round(index_length/(1024*1024*1024),2),'G') idx,
concat(round((data_length+index_length)/(1024*1024*1024),2),
'G') total_size,
round(index_length/data_length,2) idxfrac
FROM information_schema.TABLES
WHERE table_schema IN ("your_database_name")
GROUP BY table_name, table_schema, engine
ORDER BY data_length+index_length DESC LIMIT 10;
6
information_schema - overview
Największe tabele w systemie:
+--------+--------------------------------------------+-----------+---------+---------+---------+----------+
| engine | row_format | table_name | rows | data | idx | total | idxfrac |
+--------+--------------------------------------------+-----------+---------+---------+---------+----------+
| InnoDB | Compressed | events | 27273.24M | 628.49G | 837.93G | 1466.43G| 1.33 |
| InnoDB | Compressed | recipients | 2636.03M | 148.37G | 252.69G | 401.06G | 1.70 |
| InnoDB | Compressed | custom_values | 2032.97M | 81.87G | 112.06G | 193.93G | 1.37 |
| InnoDB | Compressed | devices_usage | 1451.18M | 53.48G | 36.12G | 89.60G | 0.68 |
| InnoDB | Compressed | recipients_geolocalizations | 974.06M | 42.75G | 43.63G | 86.37G | 1.02 |
| InnoDB | Compressed | events_details | 1262.98M | 29.75G | 20.78G | 50.53G | 0.70 |
| InnoDB | Compressed | blocking_information | 1090.51M | 30.92G | 13.85G | 44.77G | 0.45 |
| InnoDB | Compressed | bounce_information | 679.34M | 18.57G | 13.59G | 32.16G | 0.73 |
| InnoDB | Compressed | subscribers_activity | 601.11M | 16.69G | 15.31G | 32.00G | 0.92 |
+--------+--------------------------------------------+-----------+---------+---------+---------+----------+
7
engine
Pożądanym enginem jest InnoDB
W bardzo specyficznych warunkach może się nam opłacać utrzymywać inne
engine (np. Archive, RocksDB, TokuDB)
… WHERE
table_schema IN ("your_database_name") AND
Engine != “InnoDB” …
ALTER TABLE table_name ENGINE=InnoDB
8
row format
W przypadku InnoDB praktycznie zawsze chcemy mieć skompresowane dane
Kompresja oznacza, że mniej danych jest przesyłanych pomiędzy dyskiem a
pamięcią/procesorem
● Mniej zajętej przestrzeni na dysku
● Mniej zajętej przestrzeni w pamięci RAM (buffer pool)
● Większa utylizacja procesora (narzut na kompresję/dekompresję danych)
… WHERE
table_schema IN ("your_database_name") AND
row_format != “Compressed” …
ALTER TABLE table_name ENGINE=InnoDB ROW_FORMAT=COMPRESSED
9
rows, data size, index size, total size
rows - ilość rekordów
data size - wielkość danych w tabeli*
idx size - wielkość indeksów w tabeli
total size - sumaryczna wielkość tabeli (dane + indeksy)
* w przypadku InnoDB Primary Key jest klastrowany, więc jego wielkość liczy się
do wielkości danych, a nie indeksów
10
rows, data size, index size, total size
Wielkość (rekordy, bajty) pokazuje na jakich tabelach powinniśmy się skupić.
Warto rozważyć:
● Archiwizację
● Partycjonowanie
● Retencję danych
11
index fraction
Stosunek wielkości indeksów do danych
Im mniejszy tym lepiej (oczywiście zakładając istnienie wszystkich potrzebnych
do poprawnego działania indeksów)
Duża wartość może oznaczać niepoprawną strukturę
● Część indeksów może być niepotrzebna/nie używana
● Część indeksów może być zduplikowana
● Primary key mógł zostać wybrany nieoptymalnie (np. VARCHAR) + duża ilość secondary keys
… ORDER BY
idxfrac DESC …
12
information_schema - overview
Największe tabele w systemie:
+--------+--------------------------------------------+-----------+---------+---------+---------+----------+
| engine | row_format | table_name | rows | data | idx | total | idxfrac |
+--------+--------------------------------------------+-----------+---------+---------+---------+----------+
| InnoDB | Compressed | events | 27273.24M | 628.49G | 837.93G | 1466.43G| 1.33 |
| InnoDB | Compressed | recipients | 2636.03M | 148.37G | 252.69G | 401.06G | 1.70 |
| InnoDB | Compressed | custom_values | 2032.97M | 81.87G | 112.06G | 193.93G | 1.37 |
| InnoDB | Compressed | devices_usage | 1451.18M | 53.48G | 36.12G | 89.60G | 0.68 |
| InnoDB | Compressed | recipients_geolocalizations | 974.06M | 42.75G | 43.63G | 86.37G | 1.02 |
| InnoDB | Compressed | events_details | 1262.98M | 29.75G | 20.78G | 50.53G | 0.70 |
| InnoDB | Compressed | blocking_information | 1090.51M | 30.92G | 13.85G | 44.77G | 0.45 |
| InnoDB | Compressed | bounce_information | 679.34M | 18.57G | 13.59G | 32.16G | 0.73 |
| InnoDB | Compressed | subscribers_activity | 601.11M | 16.69G | 15.31G | 32.00G | 0.92 |
+--------+--------------------------------------------+-----------+---------+---------+---------+----------+
13
information_schema - primary key
SELECT
engine,
table_name
FROM
TABLES AS t
WHERE
NOT EXISTS(SELECT null FROM COLUMNS AS c WHERE
c.table_name = t.table_name AND
c.table_schema=t.table_schema AND
c.table_schema=’your_database_name’AND c.COLUMN_KEY='PRI'
LIMIT 1) AND t.table_schema=’your_database_name’
14
information_schema - primary key
Tabele nie posiadające PRIMARY KEY:
+--------+--------------------------------+
| engine | table_name |
+--------+--------------------------------+
| InnoDB | table_without_pk |
| InnoDB | another_one |
+--------+--------------------------------+
15
information_schema - primary key
W InnoDB zawsze powinniśmy posiadać PRIMARY KEY
● Primary Key jest klastrowany
● Jeśli nie zdefiniujemy Primary Key to InnoDB sam doda “implicite” Primary Key - w praktyce nie ma
możliwości zbudowania tabeli InnoDB bez PRIMARY KEY, tylko czasem będzie “ukryty” i nie
będziemy mieli do niego dostępu
● PRIMARY KEY ma wpływ na wielkość/budowę SECONDARY INDEX
Jeśli korzystamy z innego engine’u (np. MyISAM) może się okazać, że PRIMARY KEY faktycznie nie
jest potrzebny, ale jest to rzadkość
16
information_schema - auto increment
SELECT
TABLES.table_name,
column_name,
column_type,
auto_increment,
CASE WHEN data_type='int' AND column_type NOT LIKE '%unsigned%' THEN
auto_increment/2147483647 * 100 WHEN data_type='int' AND column_type LIKE '%unsigned%' THEN
auto_increment/4294967295 * 100 END AS capacity
FROM
information_schema.TABLES
JOIN information_schema.COLUMNS ON TABLES.table_name = COLUMNS.table_name AND
TABLES.table_schema = COLUMNS.table_schema
WHERE
TABLES.table_schema like ‘your_database_name’ AND
auto_increment IS NOT NULL AND
COLUMNS.extra='auto_increment'
ORDER BY capacity
17
information_schema - auto increment
Tabele w których kończy się zakres integer oznaczone jako auto increment:
+-----------------------------+-----------------------+------------------+----------------+----------+
| table_name | column_name | column_type | auto_increment | capacity |
+-----------------------------+-----------------------+------------------+----------------+----------+
| blocking_information | id | int(10) | 200771026 | 9.3491 |
| link_events | id | int(10) unsigned | 413384049 | 9.6248 |
| user_agent_to_subscribers | id | int(11) | 1908563772 | 88.8744 |
+-----------------------------+-----------------------+------------------+----------------+----------+
18
information_schema - auto increment
Jaki typ pola będzie najlepszy dla pola oznaczonego jako auto increment ?
● INT - wystarczy na długi czas (4 bajty - 2^32 wartości)
● BIGINT - gdy nie starcza standardowego INT (8 bajtów - 2^64 wartości)
● UNSIGNED - nie ma żadnych podstaw do tego aby mieć ujemne wartości w polu auto increment
więc zawsze stosujmy pole UNSIGNED
19
fragmentacja danych
Największe tabele w systemie:
+--------+-----------------------+-----------+---------+---------+------------+---------+---------+---------------+
| engine | table_name | rows | data | idx | total_size | on_disk | idxfrac | disk_to_mysql |
+--------+-----------------------+-----------+---------+---------+------------+---------+---------+---------------+
| InnoDB | events | 27273.95M | 628.49G | 837.93G | 1466.43G | 1522.34G| 1.33 | 1.0381 |
| InnoDB | recipients | 2636.12M | 148.37G | 252.69G | 401.06G | 471.21G | 1.70 | 1.1749 |
| InnoDB | custom_fields | 2033.00M | 81.87G | 112.06G | 193.93G | 413.15G | 1.37 | 2.1305 |
+--------+-----------------------+-----------+---------+---------+------------+---------+---------+---------------+
20
fragmentacja danych
InnoDB Compression Issue - jak powstają “wolne” przestrzenie?
● Dane trzymane są w jednostkach zwanych Page (8kB - 16kB)
● Jeśli mamy dużo operacji UPDATE to dane wcześniej mieszczące się w jednym Page, mogą się
powiększyć i nie zmieścić się w pierwotne miejsce, wtedy następuje ich przeniesienie do nowego
Page, niestety w starym pozostaje “wolne” miejsce
● Jeśli mamy dużo “losowych” operacji DELETE powstają “wolne” miejsca
● Odzyskanie miejsca następuje dopiero kiedy zajętość danych w Page spadnie poniżej 50%
Jak sobie z tym poradzić?
OPTIMIZE TABLE ‘your_table_name’ / ALTER TABLE ‘your_table_name’,
ENGINE=INNODB
21
percona toolkit
Zestaw narzędzi zbudowanych przez Percona
● W sumie ponad 30 narzędzi
● Przydatne dla administratorów/bazodanowców/deweloperów
https://www.percona.com/doc/percona-toolkit/3.0/index.html
22
pt-duplicate-key-checker
Narzędzie wyszukujące zduplikowane/niepotrzebne indexy w bazie danych
Automatycznie dostajemy propozycje konkretnego polecenia ALTER TABLE, które rozwiązuje problem
23
pt-duplicate-key-checker
########################################################################
#
# my_database.link_tags
#
########################################################################
# id_client is a left-prefix of tags
# Key definitions:
# KEY `id_client` (`id_client`)
# UNIQUE KEY `tags` (`id_client`,`tag_name`),
# Column types:
# `id_client` int(10) unsigned not null
# `tag_name` varchar(255) not null
# To remove this duplicate index, execute:
ALTER TABLE `freshmail_utf8`.`link_tags` DROP INDEX `id_client`;
24
big picture - podsumowanie
Powyższe narzędzia/metody pozwalają zgrubnie określić miejsca w których nasza baza danych ma
problemy ze strukturą
● Pozwala określić największe tabele
● Tabele które mają inny/przestarzały engine
● Tabele bez kompresji danych
● Tabele bez klucza głównego
● Tabele ze zduplikowanymi kluczami
● Tabele w których dane są mocno zfragmentowane
25
Odpowiednio
zaprojektowana struktura
26
Używaj najmniejszych możliwych typów danych
● Oczywiste… Ale czy na pewno?
Dlaczego ma to takie znaczenie?
● Wykorzystanie zasobów dyskowych
● Transfer po sieci
● Alokacja pamięci w bufforze
typy danych
27
Numeryczne typy danych
● SIGNED / UNSIGNED
● Pole typu status - TINYINT
● Pole typu active / soft delete - TINYINT
● Pole typu gender - ENUM (w rzeczywistości TINYINT) / CHAR(1)
INT vs TINYINT?
● 4 bajty vs 1 bajt
typy danych
28
Czasowe typy danych
● Pole typu last_update (bieżące zdarzenia) - TIMESTAMP
● Pole typu birthday (historia) - DATETIME
DATETIME vs TIMESTAMP
● 8 bajtów vs 4 bajty
● TIMESTAMP ma obsługę stref czasowych
typy danych
29
Znakowe typy danych
● Pole typu hash / uuid - CHAR
● Pole typu topic / name - VARCHAR
● Nie korzystaj jeśli masz słownik, np x-small, small, medium, large - ENUM
CHAR vs VARCHAR
● CHAR(4) - 4 bajty
● VARCHAR(4) - od 1 do 5 bajtów
● VARCHAR(512) - od 2 do 514 bajtów
typy danych
30
Wartość nieznana
● Jeśli pole może mieć nie znaną wartość - NULL
NULL vs NOT NULL
● NULL implementowany jest jako jeden bit
typy danych
31
CREATE TABLE `emails` (
`added` datetime DEFAULT CURRENT_TIMESTAMP,
`email` varchar(255) NOT NULL,
`type` int(11) DEFAULT '1',
`source` int(11) NOT NULL DEFAULT '2',
PRIMARY KEY (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=678023341
ROW_FORMAT=COMPRESSED
przykład
32
CREATE TABLE `emails` (
`added` datetime DEFAULT CURRENT_TIMESTAMP,
`email` varchar(255) NOT NULL,
`type` int(11) DEFAULT '1',
`source` int(11) NOT NULL DEFAULT '2',
PRIMARY KEY (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=678023341
ROW_FORMAT=COMPRESSED
przykład
33
CREATE TABLE `emails` (
`added` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`email` varchar(255) NOT NULL,
`type` tinyint NOT NULL DEFAULT '1',
`source` tinyint NOT NULL DEFAULT '2',
PRIMARY KEY (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=678023341
ROW_FORMAT=COMPRESSED
przykład
34
CREATE TABLE `emails` (
`id_emails` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`added` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`email` varchar(255) NOT NULL,
`type` tinyint NOT NULL DEFAULT '1',
`source` tinyint NOT NULL DEFAULT '2',
PRIMARY KEY (`id_emails`)
UNIQUE KEY email(`email`)
) ENGINE=InnoDB AUTO_INCREMENT=678023341
ROW_FORMAT=COMPRESSED
przykład
35
Twórz najmniej indexów jak to tylko możliwe
Wybieraj najmniejszy PRIMARY KEY jaki jest możliwy
● PRIMARY KEY jest kopiowany do każdego SECONDARY INDEX
● PRIMARY KEY jest kopiowany do każdej tabeli z którą chcemy się łączyć (FOREIGN KEY)
Unikaj “losowego” PRIMARY KEY (np. email, hash)
● INSERT jest rozrzucony po całej tabeli
Index (innodb)
36
Zmiany struktury bazy
Czyli jak przestałem się bać i
pokochałem… altery!
37
narzędzia
Natywne
● ALTER TABLE
Zewnętrzne
● pt-online-schema-change
● gh-ost
● OnlineSchemaChange
38
ALTER TABLE - stara szkoła
Każdy ALTER blokował tabelę
● Brak możliwości wykonania INSERT / UPDATE / DELETE
● Im większa tabela tym dłuższy czas zablokowania
● Można śledzić postęp tylko w przypadku file_per_table=1(za pomocą ls -la)
39
ALTER TABLE - fast index creation
Fast Index Creation
● pojawił się w Mysql 5.1 (InnoDB Plugin) lub Mysql 5.5+
● Można tworzyć Secondary Index bez konieczności kopiowania wszystkich danych w tabeli
● Przyspieszenie dodawania/kasowania indeksów.
40
ALTER TABLE - Online DDL change
InnoDB online DDL change
● Pierwsza wersja w MySQL 5.5 (podstawowe możliwości)
● Dużo więcej możliwych operacji od MySQL 5.6
● Umożliwia zmianę schematu bez blokowania tabeli
● Ograniczone do pewnych konkretnych typów operacji (np. nie obsługuje FULL TEXT)
● Dostępne tylko dla InnoDB
● Brak zarządzania “throttlingiem”
41
Algorithm
● INPLACE - nie wymaga przebudowania tabeli
● COPY - kopiuje dane i przebudowywuje całą tabelę
Lock mode
● EXCLUSIVE - żadne DML nie są możliwe
● SHARED - można z tabeli czytać, nie ma możliwości zrobić UPDATE/INSERT/DELETE
● NONE - nie ma żadnego lock’a na tabelę, można wykonywać dowolne DML
ALTER TABLE `your_database`.`table_name` ADD COLUMN `example` INT, ALGORITHM=INPLACE
ALTER TABLE `your_database`.`table_name` ENGINE=INNODB, ALGORITHM=COPY, LOCK=SHARED
ALTER TABLE - Online DDL change
42
Podczas ALTER’a tabela nie jest modyfikowana, ale za to mamy dodatkowy,
tymczasowy log file gdzie zapisywane są wszystkie zmiany dokonywane w
czasie ALTER’a na tabeli (INSERT/UPDATE/DELETE)
Wielkość log file definiuje innodb_online_alter_log_max_size
● Domyślnie 128MB
● Jeśli zostanie zapełniony, ALTER się nie powiedzie
Długo trwający ALTER może będzie powodował replication lag - najpierw w
całości musi wykonać się na masterze, potem na slave
ALTER TABLE - Online DDL change
43
Jak wygląda procedura OSC?
● Tworzymy nową tabelę z identyczną strukturą jak pierwotna
● Wykonujemy polecenia ALTER TABLE na “nowej” / pustej tabeli
● Musimy zadbać o synchronizację DML (triggers / binary log)
● Kopiujemy dane do nowej tabeli
● Zamieniamy tabele poleceniem RENAME TABLE
Online Schema Change Tools
44
Stworzone przez Percona
Udostępnione jako część pakietu Percona Toolkit
Open Source
Wykorzystuje TRIGGERY do synchronizacji (synchroniczna)
Powoduje większe obciążenie na bazie (z powodu TRIGGERÓW)
Nie mamy pełnego wpływu na “throttling”
pt-online-schema-change
45
pt-online-schema-change
pt-online-schema-change --dry-run --user=user_name
--host=127.0.0.1 --ask-pass --max-lag=2 --check-interval=1
--progress=time,10 --max-load Threads_running:50
--critical-load Threads_running:6000 --recursion-method
--chunk-time=.2
--alter-foreign-keys-method=drop_swap
dsn=D=percona,t=dsns --no-check-replication-filters
--set-vars innodb_lock_wait_timeout=10
46
Znane problemy / ograniczenia:
● Wymagany PRIMARY KEY / UNIQUE KEY
● Nazwa FOREIGN KEY ulegnie zmianie po alterze
● Na tabeli nie mogą być założone TRIGGERY
● Migracji nie można zapauzować
pt-online-schema-change
47
Stworzone przez GitHub
Open Source
Do synchronizacji wykorzystuje binloga (asynchroniczna)
Nie zakłada TRIGGERÓW na tabeli
Mamy pełny wpływ na “throttling”
Dynamicznie możemy zmieniać parametry “throttlingu”
Kontrolowany “cutover” dla nowych, zalterowanych tabel
gh-ost
48
gh-ost
gh-ost --user="4dev" --password="secret"
--host=replica.with.rbr.com
--verbose
--max-load=Threads_running=25
--critical-load=Threads_running=1000 --chunk-size=1000
--throttle-control-replicas="myreplica.1.com,myreplica.2.com
"
49
Znane problemy / ograniczenia:
⋅ Nie obsługuje aktywnej replikacji MASTER - MASTER
gh-ost
50
osc tips
screen - w razie rozłączenia z serwerem
replikacja - patrz i reaguj
DROP INDEX - wbudowany ALTER zrobi to “inplace”, nie rób tego gh-ost’em ani
ptosc
defragmentacja - --alter=”ENGINE=INNODB”
przerwanie migracji - sprawdź czy nie zostały “nowe” tabele lub triggery
51
osc - długo jeszcze?
gh-ost i ptosc pokazują progress na stdout (ale nie zawsze dokładnie)
mysql> show table status like ‘%your_table%’;
ls -alh /data/schema/*your_table*.ibd
mysql> select max(id) from your_table;
mysql> show full processlist; - żeby znaleźć aktualne ID PK
52
osc - uruchom i zapomnij...
Każda migracja wprowadza obciążenie serwera bazodanowego
Warto mieć zewnętrzne narzędzie które monitoruje średni czas odpowiedzi
aplikacji
Nie uruchamiaj w piątek wieczorem (chyba, że nie masz ochoty wrócić do
domu…)
53
chyba jestem paranoikiem...
watch -n 1 'w|head -1;echo "";mysql -e"show engine innodb
statusG"|grep -i history;echo "";df -h|grep local;echo
"";mysql -e"show processlist;"|wc -l;echo "";mysql -e"show
processlist;"|grep -v Sleep|grep -v repl’
54
Dziękuję za uwagę!
Piotr Suszalski
piotr@suszalski.pl
https://www.slideshare.net/psuszalski
Oceń mój wykład w Eventory
Pytania?

More Related Content

Featured

How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
ThinkNow
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
Kurio // The Social Media Age(ncy)
 

Featured (20)

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPT
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage Engineerings
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
 
Skeleton Culture Code
Skeleton Culture CodeSkeleton Culture Code
Skeleton Culture Code
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 

Mysql - Validate Your schema

  • 1. MySQL Validate Your Schema and change it smoothly 9 kwiecień 2018 4developers Piotr Suszalski
  • 2. agenda ● Big Picture W jakiej kondycji jest moja baza danych? Gdzie szukać potencjalnych problemów? ● Odpowiednio zaprojektowana struktura Jak projektować tabele? Jakich typów danych używać? ● Zmiany struktury bazy Jak zmienić strukturę danych w dużych tabelach (np 300GB)? 2
  • 4. od czego zacząć? ● MySQL internals ● information_schema ● Percona Toolkit ● pt-duplicate-key-checker ● pt-mysql-summary 4
  • 5. information_schema ● Baza danych ● Zawiera widoki (readonly) ● Zapewnia dostęp do metadanych o: ● tabelach ● kolumnach ● indeksach ● triggerach ● widokach ● itp. ● Można wykonywać na niej standardowe SQLki 5
  • 6. information_schema - overview SELECT engine, row_format, table_name, concat(round(table_rows/1000000,2),'M') rows, concat(round(data_length/(1024*1024*1024),2),'G') data, concat(round(index_length/(1024*1024*1024),2),'G') idx, concat(round((data_length+index_length)/(1024*1024*1024),2), 'G') total_size, round(index_length/data_length,2) idxfrac FROM information_schema.TABLES WHERE table_schema IN ("your_database_name") GROUP BY table_name, table_schema, engine ORDER BY data_length+index_length DESC LIMIT 10; 6
  • 7. information_schema - overview Największe tabele w systemie: +--------+--------------------------------------------+-----------+---------+---------+---------+----------+ | engine | row_format | table_name | rows | data | idx | total | idxfrac | +--------+--------------------------------------------+-----------+---------+---------+---------+----------+ | InnoDB | Compressed | events | 27273.24M | 628.49G | 837.93G | 1466.43G| 1.33 | | InnoDB | Compressed | recipients | 2636.03M | 148.37G | 252.69G | 401.06G | 1.70 | | InnoDB | Compressed | custom_values | 2032.97M | 81.87G | 112.06G | 193.93G | 1.37 | | InnoDB | Compressed | devices_usage | 1451.18M | 53.48G | 36.12G | 89.60G | 0.68 | | InnoDB | Compressed | recipients_geolocalizations | 974.06M | 42.75G | 43.63G | 86.37G | 1.02 | | InnoDB | Compressed | events_details | 1262.98M | 29.75G | 20.78G | 50.53G | 0.70 | | InnoDB | Compressed | blocking_information | 1090.51M | 30.92G | 13.85G | 44.77G | 0.45 | | InnoDB | Compressed | bounce_information | 679.34M | 18.57G | 13.59G | 32.16G | 0.73 | | InnoDB | Compressed | subscribers_activity | 601.11M | 16.69G | 15.31G | 32.00G | 0.92 | +--------+--------------------------------------------+-----------+---------+---------+---------+----------+ 7
  • 8. engine Pożądanym enginem jest InnoDB W bardzo specyficznych warunkach może się nam opłacać utrzymywać inne engine (np. Archive, RocksDB, TokuDB) … WHERE table_schema IN ("your_database_name") AND Engine != “InnoDB” … ALTER TABLE table_name ENGINE=InnoDB 8
  • 9. row format W przypadku InnoDB praktycznie zawsze chcemy mieć skompresowane dane Kompresja oznacza, że mniej danych jest przesyłanych pomiędzy dyskiem a pamięcią/procesorem ● Mniej zajętej przestrzeni na dysku ● Mniej zajętej przestrzeni w pamięci RAM (buffer pool) ● Większa utylizacja procesora (narzut na kompresję/dekompresję danych) … WHERE table_schema IN ("your_database_name") AND row_format != “Compressed” … ALTER TABLE table_name ENGINE=InnoDB ROW_FORMAT=COMPRESSED 9
  • 10. rows, data size, index size, total size rows - ilość rekordów data size - wielkość danych w tabeli* idx size - wielkość indeksów w tabeli total size - sumaryczna wielkość tabeli (dane + indeksy) * w przypadku InnoDB Primary Key jest klastrowany, więc jego wielkość liczy się do wielkości danych, a nie indeksów 10
  • 11. rows, data size, index size, total size Wielkość (rekordy, bajty) pokazuje na jakich tabelach powinniśmy się skupić. Warto rozważyć: ● Archiwizację ● Partycjonowanie ● Retencję danych 11
  • 12. index fraction Stosunek wielkości indeksów do danych Im mniejszy tym lepiej (oczywiście zakładając istnienie wszystkich potrzebnych do poprawnego działania indeksów) Duża wartość może oznaczać niepoprawną strukturę ● Część indeksów może być niepotrzebna/nie używana ● Część indeksów może być zduplikowana ● Primary key mógł zostać wybrany nieoptymalnie (np. VARCHAR) + duża ilość secondary keys … ORDER BY idxfrac DESC … 12
  • 13. information_schema - overview Największe tabele w systemie: +--------+--------------------------------------------+-----------+---------+---------+---------+----------+ | engine | row_format | table_name | rows | data | idx | total | idxfrac | +--------+--------------------------------------------+-----------+---------+---------+---------+----------+ | InnoDB | Compressed | events | 27273.24M | 628.49G | 837.93G | 1466.43G| 1.33 | | InnoDB | Compressed | recipients | 2636.03M | 148.37G | 252.69G | 401.06G | 1.70 | | InnoDB | Compressed | custom_values | 2032.97M | 81.87G | 112.06G | 193.93G | 1.37 | | InnoDB | Compressed | devices_usage | 1451.18M | 53.48G | 36.12G | 89.60G | 0.68 | | InnoDB | Compressed | recipients_geolocalizations | 974.06M | 42.75G | 43.63G | 86.37G | 1.02 | | InnoDB | Compressed | events_details | 1262.98M | 29.75G | 20.78G | 50.53G | 0.70 | | InnoDB | Compressed | blocking_information | 1090.51M | 30.92G | 13.85G | 44.77G | 0.45 | | InnoDB | Compressed | bounce_information | 679.34M | 18.57G | 13.59G | 32.16G | 0.73 | | InnoDB | Compressed | subscribers_activity | 601.11M | 16.69G | 15.31G | 32.00G | 0.92 | +--------+--------------------------------------------+-----------+---------+---------+---------+----------+ 13
  • 14. information_schema - primary key SELECT engine, table_name FROM TABLES AS t WHERE NOT EXISTS(SELECT null FROM COLUMNS AS c WHERE c.table_name = t.table_name AND c.table_schema=t.table_schema AND c.table_schema=’your_database_name’AND c.COLUMN_KEY='PRI' LIMIT 1) AND t.table_schema=’your_database_name’ 14
  • 15. information_schema - primary key Tabele nie posiadające PRIMARY KEY: +--------+--------------------------------+ | engine | table_name | +--------+--------------------------------+ | InnoDB | table_without_pk | | InnoDB | another_one | +--------+--------------------------------+ 15
  • 16. information_schema - primary key W InnoDB zawsze powinniśmy posiadać PRIMARY KEY ● Primary Key jest klastrowany ● Jeśli nie zdefiniujemy Primary Key to InnoDB sam doda “implicite” Primary Key - w praktyce nie ma możliwości zbudowania tabeli InnoDB bez PRIMARY KEY, tylko czasem będzie “ukryty” i nie będziemy mieli do niego dostępu ● PRIMARY KEY ma wpływ na wielkość/budowę SECONDARY INDEX Jeśli korzystamy z innego engine’u (np. MyISAM) może się okazać, że PRIMARY KEY faktycznie nie jest potrzebny, ale jest to rzadkość 16
  • 17. information_schema - auto increment SELECT TABLES.table_name, column_name, column_type, auto_increment, CASE WHEN data_type='int' AND column_type NOT LIKE '%unsigned%' THEN auto_increment/2147483647 * 100 WHEN data_type='int' AND column_type LIKE '%unsigned%' THEN auto_increment/4294967295 * 100 END AS capacity FROM information_schema.TABLES JOIN information_schema.COLUMNS ON TABLES.table_name = COLUMNS.table_name AND TABLES.table_schema = COLUMNS.table_schema WHERE TABLES.table_schema like ‘your_database_name’ AND auto_increment IS NOT NULL AND COLUMNS.extra='auto_increment' ORDER BY capacity 17
  • 18. information_schema - auto increment Tabele w których kończy się zakres integer oznaczone jako auto increment: +-----------------------------+-----------------------+------------------+----------------+----------+ | table_name | column_name | column_type | auto_increment | capacity | +-----------------------------+-----------------------+------------------+----------------+----------+ | blocking_information | id | int(10) | 200771026 | 9.3491 | | link_events | id | int(10) unsigned | 413384049 | 9.6248 | | user_agent_to_subscribers | id | int(11) | 1908563772 | 88.8744 | +-----------------------------+-----------------------+------------------+----------------+----------+ 18
  • 19. information_schema - auto increment Jaki typ pola będzie najlepszy dla pola oznaczonego jako auto increment ? ● INT - wystarczy na długi czas (4 bajty - 2^32 wartości) ● BIGINT - gdy nie starcza standardowego INT (8 bajtów - 2^64 wartości) ● UNSIGNED - nie ma żadnych podstaw do tego aby mieć ujemne wartości w polu auto increment więc zawsze stosujmy pole UNSIGNED 19
  • 20. fragmentacja danych Największe tabele w systemie: +--------+-----------------------+-----------+---------+---------+------------+---------+---------+---------------+ | engine | table_name | rows | data | idx | total_size | on_disk | idxfrac | disk_to_mysql | +--------+-----------------------+-----------+---------+---------+------------+---------+---------+---------------+ | InnoDB | events | 27273.95M | 628.49G | 837.93G | 1466.43G | 1522.34G| 1.33 | 1.0381 | | InnoDB | recipients | 2636.12M | 148.37G | 252.69G | 401.06G | 471.21G | 1.70 | 1.1749 | | InnoDB | custom_fields | 2033.00M | 81.87G | 112.06G | 193.93G | 413.15G | 1.37 | 2.1305 | +--------+-----------------------+-----------+---------+---------+------------+---------+---------+---------------+ 20
  • 21. fragmentacja danych InnoDB Compression Issue - jak powstają “wolne” przestrzenie? ● Dane trzymane są w jednostkach zwanych Page (8kB - 16kB) ● Jeśli mamy dużo operacji UPDATE to dane wcześniej mieszczące się w jednym Page, mogą się powiększyć i nie zmieścić się w pierwotne miejsce, wtedy następuje ich przeniesienie do nowego Page, niestety w starym pozostaje “wolne” miejsce ● Jeśli mamy dużo “losowych” operacji DELETE powstają “wolne” miejsca ● Odzyskanie miejsca następuje dopiero kiedy zajętość danych w Page spadnie poniżej 50% Jak sobie z tym poradzić? OPTIMIZE TABLE ‘your_table_name’ / ALTER TABLE ‘your_table_name’, ENGINE=INNODB 21
  • 22. percona toolkit Zestaw narzędzi zbudowanych przez Percona ● W sumie ponad 30 narzędzi ● Przydatne dla administratorów/bazodanowców/deweloperów https://www.percona.com/doc/percona-toolkit/3.0/index.html 22
  • 23. pt-duplicate-key-checker Narzędzie wyszukujące zduplikowane/niepotrzebne indexy w bazie danych Automatycznie dostajemy propozycje konkretnego polecenia ALTER TABLE, które rozwiązuje problem 23
  • 24. pt-duplicate-key-checker ######################################################################## # # my_database.link_tags # ######################################################################## # id_client is a left-prefix of tags # Key definitions: # KEY `id_client` (`id_client`) # UNIQUE KEY `tags` (`id_client`,`tag_name`), # Column types: # `id_client` int(10) unsigned not null # `tag_name` varchar(255) not null # To remove this duplicate index, execute: ALTER TABLE `freshmail_utf8`.`link_tags` DROP INDEX `id_client`; 24
  • 25. big picture - podsumowanie Powyższe narzędzia/metody pozwalają zgrubnie określić miejsca w których nasza baza danych ma problemy ze strukturą ● Pozwala określić największe tabele ● Tabele które mają inny/przestarzały engine ● Tabele bez kompresji danych ● Tabele bez klucza głównego ● Tabele ze zduplikowanymi kluczami ● Tabele w których dane są mocno zfragmentowane 25
  • 27. Używaj najmniejszych możliwych typów danych ● Oczywiste… Ale czy na pewno? Dlaczego ma to takie znaczenie? ● Wykorzystanie zasobów dyskowych ● Transfer po sieci ● Alokacja pamięci w bufforze typy danych 27
  • 28. Numeryczne typy danych ● SIGNED / UNSIGNED ● Pole typu status - TINYINT ● Pole typu active / soft delete - TINYINT ● Pole typu gender - ENUM (w rzeczywistości TINYINT) / CHAR(1) INT vs TINYINT? ● 4 bajty vs 1 bajt typy danych 28
  • 29. Czasowe typy danych ● Pole typu last_update (bieżące zdarzenia) - TIMESTAMP ● Pole typu birthday (historia) - DATETIME DATETIME vs TIMESTAMP ● 8 bajtów vs 4 bajty ● TIMESTAMP ma obsługę stref czasowych typy danych 29
  • 30. Znakowe typy danych ● Pole typu hash / uuid - CHAR ● Pole typu topic / name - VARCHAR ● Nie korzystaj jeśli masz słownik, np x-small, small, medium, large - ENUM CHAR vs VARCHAR ● CHAR(4) - 4 bajty ● VARCHAR(4) - od 1 do 5 bajtów ● VARCHAR(512) - od 2 do 514 bajtów typy danych 30
  • 31. Wartość nieznana ● Jeśli pole może mieć nie znaną wartość - NULL NULL vs NOT NULL ● NULL implementowany jest jako jeden bit typy danych 31
  • 32. CREATE TABLE `emails` ( `added` datetime DEFAULT CURRENT_TIMESTAMP, `email` varchar(255) NOT NULL, `type` int(11) DEFAULT '1', `source` int(11) NOT NULL DEFAULT '2', PRIMARY KEY (`email`) ) ENGINE=InnoDB AUTO_INCREMENT=678023341 ROW_FORMAT=COMPRESSED przykład 32
  • 33. CREATE TABLE `emails` ( `added` datetime DEFAULT CURRENT_TIMESTAMP, `email` varchar(255) NOT NULL, `type` int(11) DEFAULT '1', `source` int(11) NOT NULL DEFAULT '2', PRIMARY KEY (`email`) ) ENGINE=InnoDB AUTO_INCREMENT=678023341 ROW_FORMAT=COMPRESSED przykład 33
  • 34. CREATE TABLE `emails` ( `added` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `email` varchar(255) NOT NULL, `type` tinyint NOT NULL DEFAULT '1', `source` tinyint NOT NULL DEFAULT '2', PRIMARY KEY (`email`) ) ENGINE=InnoDB AUTO_INCREMENT=678023341 ROW_FORMAT=COMPRESSED przykład 34
  • 35. CREATE TABLE `emails` ( `id_emails` INT UNSIGNED NOT NULL AUTO_INCREMENT, `added` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `email` varchar(255) NOT NULL, `type` tinyint NOT NULL DEFAULT '1', `source` tinyint NOT NULL DEFAULT '2', PRIMARY KEY (`id_emails`) UNIQUE KEY email(`email`) ) ENGINE=InnoDB AUTO_INCREMENT=678023341 ROW_FORMAT=COMPRESSED przykład 35
  • 36. Twórz najmniej indexów jak to tylko możliwe Wybieraj najmniejszy PRIMARY KEY jaki jest możliwy ● PRIMARY KEY jest kopiowany do każdego SECONDARY INDEX ● PRIMARY KEY jest kopiowany do każdej tabeli z którą chcemy się łączyć (FOREIGN KEY) Unikaj “losowego” PRIMARY KEY (np. email, hash) ● INSERT jest rozrzucony po całej tabeli Index (innodb) 36
  • 37. Zmiany struktury bazy Czyli jak przestałem się bać i pokochałem… altery! 37
  • 38. narzędzia Natywne ● ALTER TABLE Zewnętrzne ● pt-online-schema-change ● gh-ost ● OnlineSchemaChange 38
  • 39. ALTER TABLE - stara szkoła Każdy ALTER blokował tabelę ● Brak możliwości wykonania INSERT / UPDATE / DELETE ● Im większa tabela tym dłuższy czas zablokowania ● Można śledzić postęp tylko w przypadku file_per_table=1(za pomocą ls -la) 39
  • 40. ALTER TABLE - fast index creation Fast Index Creation ● pojawił się w Mysql 5.1 (InnoDB Plugin) lub Mysql 5.5+ ● Można tworzyć Secondary Index bez konieczności kopiowania wszystkich danych w tabeli ● Przyspieszenie dodawania/kasowania indeksów. 40
  • 41. ALTER TABLE - Online DDL change InnoDB online DDL change ● Pierwsza wersja w MySQL 5.5 (podstawowe możliwości) ● Dużo więcej możliwych operacji od MySQL 5.6 ● Umożliwia zmianę schematu bez blokowania tabeli ● Ograniczone do pewnych konkretnych typów operacji (np. nie obsługuje FULL TEXT) ● Dostępne tylko dla InnoDB ● Brak zarządzania “throttlingiem” 41
  • 42. Algorithm ● INPLACE - nie wymaga przebudowania tabeli ● COPY - kopiuje dane i przebudowywuje całą tabelę Lock mode ● EXCLUSIVE - żadne DML nie są możliwe ● SHARED - można z tabeli czytać, nie ma możliwości zrobić UPDATE/INSERT/DELETE ● NONE - nie ma żadnego lock’a na tabelę, można wykonywać dowolne DML ALTER TABLE `your_database`.`table_name` ADD COLUMN `example` INT, ALGORITHM=INPLACE ALTER TABLE `your_database`.`table_name` ENGINE=INNODB, ALGORITHM=COPY, LOCK=SHARED ALTER TABLE - Online DDL change 42
  • 43. Podczas ALTER’a tabela nie jest modyfikowana, ale za to mamy dodatkowy, tymczasowy log file gdzie zapisywane są wszystkie zmiany dokonywane w czasie ALTER’a na tabeli (INSERT/UPDATE/DELETE) Wielkość log file definiuje innodb_online_alter_log_max_size ● Domyślnie 128MB ● Jeśli zostanie zapełniony, ALTER się nie powiedzie Długo trwający ALTER może będzie powodował replication lag - najpierw w całości musi wykonać się na masterze, potem na slave ALTER TABLE - Online DDL change 43
  • 44. Jak wygląda procedura OSC? ● Tworzymy nową tabelę z identyczną strukturą jak pierwotna ● Wykonujemy polecenia ALTER TABLE na “nowej” / pustej tabeli ● Musimy zadbać o synchronizację DML (triggers / binary log) ● Kopiujemy dane do nowej tabeli ● Zamieniamy tabele poleceniem RENAME TABLE Online Schema Change Tools 44
  • 45. Stworzone przez Percona Udostępnione jako część pakietu Percona Toolkit Open Source Wykorzystuje TRIGGERY do synchronizacji (synchroniczna) Powoduje większe obciążenie na bazie (z powodu TRIGGERÓW) Nie mamy pełnego wpływu na “throttling” pt-online-schema-change 45
  • 46. pt-online-schema-change pt-online-schema-change --dry-run --user=user_name --host=127.0.0.1 --ask-pass --max-lag=2 --check-interval=1 --progress=time,10 --max-load Threads_running:50 --critical-load Threads_running:6000 --recursion-method --chunk-time=.2 --alter-foreign-keys-method=drop_swap dsn=D=percona,t=dsns --no-check-replication-filters --set-vars innodb_lock_wait_timeout=10 46
  • 47. Znane problemy / ograniczenia: ● Wymagany PRIMARY KEY / UNIQUE KEY ● Nazwa FOREIGN KEY ulegnie zmianie po alterze ● Na tabeli nie mogą być założone TRIGGERY ● Migracji nie można zapauzować pt-online-schema-change 47
  • 48. Stworzone przez GitHub Open Source Do synchronizacji wykorzystuje binloga (asynchroniczna) Nie zakłada TRIGGERÓW na tabeli Mamy pełny wpływ na “throttling” Dynamicznie możemy zmieniać parametry “throttlingu” Kontrolowany “cutover” dla nowych, zalterowanych tabel gh-ost 48
  • 50. Znane problemy / ograniczenia: ⋅ Nie obsługuje aktywnej replikacji MASTER - MASTER gh-ost 50
  • 51. osc tips screen - w razie rozłączenia z serwerem replikacja - patrz i reaguj DROP INDEX - wbudowany ALTER zrobi to “inplace”, nie rób tego gh-ost’em ani ptosc defragmentacja - --alter=”ENGINE=INNODB” przerwanie migracji - sprawdź czy nie zostały “nowe” tabele lub triggery 51
  • 52. osc - długo jeszcze? gh-ost i ptosc pokazują progress na stdout (ale nie zawsze dokładnie) mysql> show table status like ‘%your_table%’; ls -alh /data/schema/*your_table*.ibd mysql> select max(id) from your_table; mysql> show full processlist; - żeby znaleźć aktualne ID PK 52
  • 53. osc - uruchom i zapomnij... Każda migracja wprowadza obciążenie serwera bazodanowego Warto mieć zewnętrzne narzędzie które monitoruje średni czas odpowiedzi aplikacji Nie uruchamiaj w piątek wieczorem (chyba, że nie masz ochoty wrócić do domu…) 53
  • 54. chyba jestem paranoikiem... watch -n 1 'w|head -1;echo "";mysql -e"show engine innodb statusG"|grep -i history;echo "";df -h|grep local;echo "";mysql -e"show processlist;"|wc -l;echo "";mysql -e"show processlist;"|grep -v Sleep|grep -v repl’ 54
  • 55. Dziękuję za uwagę! Piotr Suszalski piotr@suszalski.pl https://www.slideshare.net/psuszalski Oceń mój wykład w Eventory Pytania?