Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Odpytywanie schematu informacyjnego MySQL:Dlaczego? Jak?

Bazy danych muszą działać optymalnie, ale to nie jest takie proste zadanie. Baza danych INFORMATION SCHEMA może być Twoją tajną bronią w wojnie o optymalizację baz danych.

Jesteśmy przyzwyczajeni do tworzenia baz danych za pomocą interfejsu graficznego lub serii poleceń SQL. To całkowicie w porządku, ale dobrze jest też trochę zrozumieć, co dzieje się w tle. Jest to ważne przy tworzeniu, utrzymywaniu i optymalizacji bazy danych, a także jest dobrym sposobem na śledzenie zmian zachodzących „za kulisami”.

W tym artykule przyjrzymy się kilku zapytaniom SQL, które mogą pomóc Ci zajrzeć do działania bazy danych MySQL.

Baza danych INFORMATION_SCHEMA

Omówiliśmy już INFORMATION_SCHEMA w tym artykule. Jeśli jeszcze tego nie przeczytałeś, zdecydowanie sugeruję, abyś to zrobił przed kontynuowaniem.

Jeśli potrzebujesz odświeżenia na INFORMATION_SCHEMA baza danych – lub jeśli zdecydujesz się nie czytać pierwszego artykułu – oto kilka podstawowych faktów, które musisz wiedzieć:

  • INFORMATION_SCHEMA baza danych jest częścią standardu ANSI. Będziemy pracować z MySQL, ale inne RDBMS mają swoje warianty. Możesz znaleźć wersje dla H2 Database, HSQLDB, MariaDB, Microsoft SQL Server i PostgreSQL.
  • To jest baza danych, która śledzi wszystkie inne bazy danych na serwerze; tutaj znajdziemy opisy wszystkich obiektów.
  • Jak każda inna baza danych, INFORMATION_SCHEMA baza danych zawiera szereg powiązanych tabel i informacji o różnych obiektach.
  • Możesz wysłać zapytanie do tej bazy danych za pomocą SQL i użyć wyników do:
    • Monitoruj stan i wydajność bazy danych oraz
    • Automatycznie generuj kod na podstawie wyników zapytania.

Przejdźmy teraz do odpytywania bazy danych INFORMATION_SCHEMA. Zaczniemy od przyjrzenia się modelowi danych, którego będziemy używać.

Model danych

Model, którego użyjemy w tym artykule, pokazano poniżej.




Jest to uproszczony model, który pozwala nam przechowywać informacje o zajęciach, instruktorach, uczniach i inne powiązane szczegóły. Przyjrzyjmy się pokrótce tabelom.

Przechowamy listę instruktorów u lecturer stół. Dla każdego wykładowcy zarejestrujemy first_name i last_name .

class tabela zawiera listę wszystkich klas jakie mamy w naszej szkole. Dla każdego rekordu w tej tabeli będziemy przechowywać class_name , identyfikator wykładowcy, planowana start_date i end_date i wszelkie dodatkowe class_details . Dla uproszczenia zakładam, że mamy tylko jednego wykładowcę na zajęcia.

Zajęcia są zwykle organizowane w formie serii wykładów. Zwykle wymagają jednego lub więcej egzaminów. Będziemy przechowywać listy powiązanych wykładów i egzaminów w lecture i exam tabele. Oba będą miały identyfikator powiązanej klasy i oczekiwany start_time i end_time .

Teraz potrzebujemy studentów na nasze zajęcia. Lista wszystkich uczniów jest przechowywana w student stół. Po raz kolejny będziemy przechowywać tylko first_name i last_name każdego ucznia.

Ostatnią rzeczą, którą musimy zrobić, to śledzić działania uczniów. Przechowamy listę wszystkich zajęć, na które zapisał się uczeń, listę obecności uczniów i wyniki ich egzaminów. Każda z pozostałych trzech tabel – on_class , on_lecture i on_exam – będzie miał odniesienie do ucznia i odniesienie do odpowiedniej tabeli. Tylko on_exam tabela będzie miała dodatkową wartość:ocena.

Tak, ten model jest bardzo prosty. Moglibyśmy dodać wiele innych szczegółów dotyczących studentów, wykładowców i zajęć. Możemy przechowywać wartości historyczne, gdy rekordy są aktualizowane lub usuwane. Mimo to ten model wystarczy do celów tego artykułu.

Tworzenie bazy danych

Jesteśmy gotowi do stworzenia bazy danych na naszym lokalnym serwerze i zbadania, co się w niej dzieje. Wyeksportujemy model (w Vertabelo) za pomocą „Generate SQL script " przycisk.

Następnie utworzymy bazę danych na instancji MySQL Server. Nazwałem swoją bazę danych „classes_and_students ”.

Następną rzeczą, którą musimy zrobić, jest uruchomienie wcześniej wygenerowanego skryptu SQL.

Teraz mamy bazę danych ze wszystkimi jej obiektami (tabele, klucze główne i obce, klucze alternatywne).

Rozmiar bazy danych

Po uruchomieniu skryptu dane o „classes and students ” baza danych jest przechowywana w INFORMATION_SCHEMA Baza danych. Te dane znajdują się w wielu różnych tabelach. Nie będę ich tutaj wymieniać ponownie; zrobiliśmy to w poprzednim artykule.

Zobaczmy, jak możemy użyć standardowego SQL na tej bazie danych. Zacznę od jednego bardzo ważnego zapytania:

SET @table_schema = "classes_and_students";

SELECT 

    ROUND(SUM( INFORMATION_SCHEMA.TABLES.DATA_LENGTH + INFORMATION_SCHEMA.TABLES.INDEX_LENGTH ) / 1024 / 1024, 2) AS "DB Size (in MB)",
    ROUND(SUM( INFORMATION_SCHEMA.TABLES.DATA_FREE )/ 1024 / 1024, 2) AS "Free Space (in MB)"
    
FROM INFORMATION_SCHEMA.TABLES
WHERE INFORMATION_SCHEMA.TABLES.TABLE_SCHEMA = @table_schema;

Pytamy tylko o INFORMATION_SCHEMA.TABLES tabela tutaj. Ta tabela powinna dać nam więcej niż wystarczająco dużo szczegółów na temat wszystkich tabel na serwerze. Pamiętaj, że odfiltrowałem tylko tabele z „classes_and_students " bazy danych przy użyciu SET zmienna w pierwszym wierszu, a później używając tej wartości w zapytaniu. Większość tabel zawiera kolumny TABLE_NAME i TABLE_SCHEMA , które oznaczają tabelę i schemat/bazę danych, do której należą te dane.

To zapytanie zwróci aktualny rozmiar naszej bazy danych i wolne miejsce zarezerwowane dla naszej bazy danych. Oto rzeczywisty wynik:

Zgodnie z oczekiwaniami rozmiar naszej pustej bazy danych jest mniejszy niż 1 MB, a zarezerwowane wolne miejsce jest znacznie większe.

Rozmiary i właściwości tabel

Następną interesującą rzeczą do zrobienia byłoby przyjrzenie się rozmiarom tabel w naszej bazie danych. W tym celu użyjemy następującego zapytania:

SET @table_schema = "classes_and_students";

SELECT 

	INFORMATION_SCHEMA.TABLES.TABLE_NAME,
    ROUND(SUM( INFORMATION_SCHEMA.TABLES.DATA_LENGTH + INFORMATION_SCHEMA.TABLES.INDEX_LENGTH ) / 1024 / 1024, 2) "Table Size (in MB)",
	ROUND(SUM( INFORMATION_SCHEMA.TABLES.DATA_FREE )/ 1024 / 1024, 2) AS "Free Space (in MB)",
	MAX( INFORMATION_SCHEMA.TABLES.TABLE_ROWS) AS table_rows_number,
	MAX( INFORMATION_SCHEMA.TABLES.AUTO_INCREMENT) AS auto_increment_value

FROM INFORMATION_SCHEMA.TABLES
WHERE INFORMATION_SCHEMA.TABLES.TABLE_SCHEMA = @table_schema
GROUP BY INFORMATION_SCHEMA.TABLES.TABLE_NAME
ORDER BY 2 DESC;

Zapytanie jest prawie identyczne jak poprzednie, z jednym wyjątkiem:wynik jest pogrupowany na poziomie tabeli.

Oto obraz wyniku zwróconego przez to zapytanie:

Po pierwsze, możemy zauważyć, że wszystkie osiem stołów ma minimalny „Rozmiar stołu” zarezerwowane dla definicji tabeli, która obejmuje kolumny, klucz podstawowy i indeks. „Wolna przestrzeń” jest równomiernie rozłożony na wszystkie stoły.

Możemy również zobaczyć liczbę wierszy aktualnie w każdej tabeli i bieżącą wartość auto_increment właściwość dla każdej tabeli. Ponieważ wszystkie tabele są całkowicie puste, nie mamy danych i auto_increment jest ustawiona na 1 (wartość, która zostanie przypisana do następnego wstawionego wiersza).

Klucze główne

Każda tabela powinna mieć zdefiniowaną wartość klucza podstawowego, więc dobrze jest sprawdzić, czy jest to prawdą dla naszej bazy danych. Jednym ze sposobów, aby to zrobić, jest połączenie listy wszystkich tabel z listą ograniczeń. To powinno dać nam potrzebne informacje.

SET @table_schema = "classes_and_students";

SELECT 

	tab.TABLE_NAME,
    COUNT(*) AS PRI_number

FROM INFORMATION_SCHEMA.TABLES tab
LEFT JOIN (
    SELECT

        INFORMATION_SCHEMA.COLUMNS.TABLE_SCHEMA,
        INFORMATION_SCHEMA.COLUMNS.TABLE_NAME

    FROM INFORMATION_SCHEMA.COLUMNS
    WHERE INFORMATION_SCHEMA.COLUMNS.TABLE_SCHEMA  = @table_schema
    AND INFORMATION_SCHEMA.COLUMNS.COLUMN_KEY = 'PRI'
) col 
	ON tab.TABLE_SCHEMA = col.TABLE_SCHEMA
    AND tab.TABLE_NAME = col.TABLE_NAME
WHERE tab.TABLE_SCHEMA = @table_schema
GROUP BY 
	tab.TABLE_NAME;

Użyliśmy również INFORMATION_SCHEMA.COLUMNS tabela w tym zapytaniu. Podczas gdy pierwsza część zapytania po prostu zwróci wszystkie tabele w bazie danych, druga część (po LEFT JOIN ) policzy liczbę PRI w tych tabelach. Użyliśmy LEFT JOIN ponieważ chcemy sprawdzić, czy tabela ma 0 PRI w COLUMNS tabela.

Zgodnie z oczekiwaniami, każda tabela w naszej bazie danych zawiera dokładnie jedną kolumnę klucza podstawowego (PRI).

„Wyspy”?

„Wyspy” to stoły całkowicie oddzielone od reszty modelu. Zdarzają się, gdy tabela nie zawiera kluczy obcych i nie ma do niej odniesień w żadnej innej tabeli. To naprawdę nie powinno mieć miejsca, chyba że istnieje naprawdę dobry powód, np. gdy tabele zawierają parametry lub przechowują wyniki lub raporty wewnątrz modelu.

SET @table_schema = "classes_and_students";

SELECT 

	tab.TABLE_NAME,
    (CASE WHEN f1.number_referenced IS NULL THEN 0 ELSE f1.number_referenced END) AS number_referenced,
    (CASE WHEN f2.number_referencing IS NULL THEN 0 ELSE f2.number_referencing END) AS number_referencing

FROM INFORMATION_SCHEMA.TABLES tab
LEFT JOIN 

-- # table was used as a reference
(
    SELECT 
        INFORMATION_SCHEMA.KEY_COLUMN_USAGE.REFERENCED_TABLE_SCHEMA,
        INFORMATION_SCHEMA.KEY_COLUMN_USAGE.REFERENCED_TABLE_NAME,
        COUNT(*) AS number_referenced
    FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE 
    WHERE INFORMATION_SCHEMA.KEY_COLUMN_USAGE.REFERENCED_TABLE_SCHEMA = @table_schema
    GROUP BY
        INFORMATION_SCHEMA.KEY_COLUMN_USAGE.REFERENCED_TABLE_SCHEMA,
        INFORMATION_SCHEMA.KEY_COLUMN_USAGE.REFERENCED_TABLE_NAME
) f1 
	ON tab.TABLE_SCHEMA = f1.REFERENCED_TABLE_SCHEMA
    AND tab.TABLE_NAME = f1.REFERENCED_TABLE_NAME

LEFT JOIN

-- # of references in the table
(
    SELECT 
        INFORMATION_SCHEMA.KEY_COLUMN_USAGE.TABLE_SCHEMA,
        INFORMATION_SCHEMA.KEY_COLUMN_USAGE.TABLE_NAME,
        COUNT(*) AS number_referencing
    FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE 
    WHERE INFORMATION_SCHEMA.KEY_COLUMN_USAGE.REFERENCED_TABLE_SCHEMA = @table_schema
    AND INFORMATION_SCHEMA.KEY_COLUMN_USAGE.REFERENCED_TABLE_NAME IS NOT NULL
    GROUP BY
        INFORMATION_SCHEMA.KEY_COLUMN_USAGE.TABLE_SCHEMA,
        INFORMATION_SCHEMA.KEY_COLUMN_USAGE.TABLE_NAME
) f2 
	ON tab.TABLE_SCHEMA = f2.TABLE_SCHEMA
    AND tab.TABLE_NAME = f2.TABLE_NAME    
    
WHERE tab.TABLE_SCHEMA = @table_schema;

Jaka jest idea tego zapytania? Cóż, używamy INFORMATION_SCHEMA.KEY_COLUMN_USAGE tabela, aby sprawdzić, czy jakakolwiek kolumna w tabeli jest odniesieniem do innej tabeli lub czy jakakolwiek kolumna jest używana jako odwołanie w dowolnej innej tabeli. Pierwsza część zapytania wybiera wszystkie tabele. Po pierwszym LEFT JOIN zliczamy, ile razy dowolna kolumna z tej tabeli została użyta jako odwołanie. Po drugim LEFT JOIN liczymy, ile razy dowolna kolumna z tej tabeli odwoływała się do dowolnej innej tabeli.

Zwrócony wynik to:

W wierszu dla class tabeli, liczby 3 i 1 wskazują, że do tej tabeli odwołano się trzykrotnie (w lecture , exam i on_class tabel) i zawiera jeden atrybut odwołujący się do innej tabeli (lecturer_id ). Pozostałe tabele mają podobny wzór, chociaż rzeczywiste liczby będą oczywiście inne. Zasada jest taka, że ​​żaden wiersz nie powinien mieć 0 w obu kolumnach.

Dodawanie wierszy

Jak dotąd wszystko poszło zgodnie z oczekiwaniami. Pomyślnie zaimportowaliśmy nasz model danych z Vertabelo do lokalnego serwera MySQL. Wszystkie tabele zawierają klucze, tak jak tego chcemy, a wszystkie tabele są ze sobą powiązane – w naszym modelu nie ma „wysp”.

Teraz wstawimy kilka wierszy do naszych tabel i użyjemy wcześniej zademonstrowanych zapytań do śledzenia zmian w naszej bazie danych.

Po dodaniu 1000 wierszy w tabeli wykładowcy ponownie uruchomimy zapytanie z „Table Sizes and Properties " Sekcja. Zwróci następujący wynik:

Możemy łatwo zauważyć, że liczba wierszy i wartości auto_increment zmieniły się zgodnie z oczekiwaniami, ale nie nastąpiła znacząca zmiana w rozmiarze tabeli.

To był tylko przykład testowy; w rzeczywistych sytuacjach zauważylibyśmy znaczące zmiany. Liczba wierszy zmieni się drastycznie w tabelach wypełnianych przez użytkowników lub zautomatyzowane procesy (tj. tabele, które nie są słownikami). Sprawdzanie rozmiaru i wartości w takich tabelach to bardzo dobry sposób na szybkie znalezienie i poprawienie niepożądanego zachowania.

Chcesz udostępnić?

Praca z bazami danych to ciągłe dążenie do optymalnej wydajności. Aby odnieść większy sukces w tym dążeniu, powinieneś użyć dowolnego dostępnego narzędzia. Dziś widzieliśmy kilka zapytań, które przydają się w naszej walce o lepszą wydajność. Czy znalazłeś coś jeszcze przydatnego? Czy grałeś z INFORMATION_SCHEMA? baza danych przed? Podziel się swoim doświadczeniem w komentarzach poniżej.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. MySQL InnoDB nie zwalnia miejsca na dysku po usunięciu wierszy danych z tabeli

  2. Jak klastrować systemy równoważenia obciążenia ProxySQL

  3. automatyczny przyrost pierwotny pozostawiając przerwy w liczeniu

  4. Dlaczego MySQL pozwala na grupowanie według zapytań BEZ funkcji agregujących?

  5. Korzystanie z funkcji agregujących (SUM, AVG, MAX, MIN, COUNT, DISTINCT) w MySQL