Partycjonowanie tabeli - nauka

Partycjonowanie tabeli - nauka
P1
  • Rejestracja:prawie 8 lat
  • Ostatnio:około miesiąc
  • Postów:4
0

Witam, od jakiegoś czasu zagłębiam się w administrowanie MSSQL i miałbym prośbę o sprawdzenie, czy dobrze rozumiem aspekt partycjonowania tabel. Gdy uczyłem się partycjonować korzystałem z różnych książek, tutoriali, czy informacji w internecie, gdzie zazwyczaj partycjonowanie odbywało się za pomocą lat, czy miesięcy. W Tabeli, którą chce partycjonować nie mam takiego odniesienia. Tabela składa się z trzech kolumn tj. id (liczby od 1 i dalej), relation_id (liczby od 1779698 do 682498137) i position (zamienne znaki liter i liczb, np. R3535, które mogą sie powtarzac). Uznałem, że najlepsza do partycjonowania byłaby kolumna relation_id. Poniżej mój kod, którym to zrobiłem:

Stworzyłem pliki i grupy plików względem kolumny relation_id

Kopiuj
-- Dodanie nowych grup plików
ALTER DATABASE mip1 
ADD FILEGROUP relation_id_100kk; 

ALTER DATABASE mip1 
ADD FILEGROUP relation_id_200kk; 

ALTER DATABASE mip1 
ADD FILEGROUP relation_id_300kk; 

ALTER DATABASE mip1 
ADD FILEGROUP relation_id_400kk; 

ALTER DATABASE mip1 
ADD FILEGROUP relation_id_500kk; 

ALTER DATABASE mip1 
ADD FILEGROUP relation_id_600kk; 

ALTER DATABASE mip1 
ADD FILEGROUP relation_id_700kk;


-- Dodanie nowych plików do nowych grup plików
ALTER DATABASE mip1 
ADD FILE  
( 
    NAME = 'relation_id_100kk',  
    FILENAME = 'P:\relation_id_100kk.ndf',  
    SIZE = 50GB,  
    MAXSIZE = 70GB,  
    FILEGROWTH = 1024MB  
) 
TO FILEGROUP relation_id_100kk; 

ALTER DATABASE mip1 
ADD FILE  
( 
    NAME = 'relation_id_200kk',  
    FILENAME = 'P:\relation_id_200kk.ndf',  
    SIZE = 50GB,  
    MAXSIZE = 70GB,  
    FILEGROWTH = 1024MB  
) 
TO FILEGROUP relation_id_200kk; 

ALTER DATABASE mip1 
ADD FILE  
( 
    NAME = 'relation_id_300kk',  
    FILENAME = 'P:\relation_id_300kk.ndf',  
    SIZE = 50GB,  
    MAXSIZE = 70GB,  
    FILEGROWTH = 1024MB  
) 
TO FILEGROUP relation_id_300kk; 

ALTER DATABASE mip1 
ADD FILE  
( 
    NAME = 'relation_id_400kk',  
    FILENAME = 'P:\relation_id_400kk.ndf',  
    SIZE = 50GB,  
    MAXSIZE = 70GB,  
    FILEGROWTH = 1024MB  
) 
TO FILEGROUP relation_id_400kk; 

ALTER DATABASE mip1 
ADD FILE  
( 
    NAME = 'relation_id_500kk',  
    FILENAME = 'P:\relation_id_500kk.ndf',  
    SIZE = 50GB,  
    MAXSIZE = 70GB,  
    FILEGROWTH = 1024MB  
) 
TO FILEGROUP relation_id_500kk; 

ALTER DATABASE mip1 
ADD FILE  
( 
    NAME = 'relation_id_600kk',  
    FILENAME = 'P:\relation_id_600kk.ndf',  
    SIZE = 50GB,  
    MAXSIZE = 70GB,  
    FILEGROWTH = 1024MB  
) 
TO FILEGROUP relation_id_600kk; 

ALTER DATABASE mip1 
ADD FILE  
( 
    NAME = 'relation_id_700kk',  
    FILENAME = 'P:\relation_id_700kk.ndf',  
    SIZE = 50GB,  
    MAXSIZE = 70GB,  
    FILEGROWTH = 1024MB  
) 
TO FILEGROUP relation_id_700kk;

Stworzyłem funkcje partycji:

Kopiuj
CREATE PARTITION FUNCTION PartitionFunction_Relation_Id (bigint)
AS RANGE LEFT FOR VALUES (
    100000000, 
    200000000, 
    300000000, 
    400000000, 
    500000000, 
    600000000
);

Schemat partycjonowania

Kopiuj

CREATE PARTITION SCHEME PartitionScheme_Relation_Id
AS PARTITION PartitionFunction_Relation_Id
TO (
    relation_id_100kk, 
    relation_id_200kk, 
    relation_id_300kk, 
    relation_id_400kk, 
    relation_id_500kk, 
    relation_id_600kk, 
    relation_id_700kk
);

Stworzyłem nową tabelę taką jak tą, którą chce partycjonowac:

Kopiuj

CREATE TABLE [mipadm].[u_tt_batch_relation_mounting_positions_partitioned](
    [id] [bigint] IDENTITY(1,1) NOT NULL,
	[tt_relation_id] [bigint] NOT NULL,
	[position] [nvarchar](20) NOT NULL,
 CONSTRAINT [PK_u_tt_batch_relation_mounting_positions_partitioned] PRIMARY KEY CLUSTERED 
(
	[id] ASC, [tt_relation_id]
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF)
) ON PartitionScheme_Relation_Id(tt_relation_id);

Przeniesienie danych ze starej tabeli:

Kopiuj
INSERT INTO [mipadm].[u_tt_batch_relation_mounting_positions_partitioned] ([tt_relation_id], [position])
SELECT [tt_relation_id], [position]
FROM [mipadm].[u_tt_batch_relation_mounting_positions];

Usuniecie starej tabeli:

Kopiuj
DROP TABLE [mipadm].[u_tt_batch_relation_mounting_positions];

Zmiana nazwy:

Kopiuj
EXEC sp_rename 'mipadm.u_tt_batch_relation_mounting_positions_partitioned', 'u_tt_batch_relation_mounting_positions';

Dodatkowo zrobiłem indeksy tak samo jak na starej tabeli:

Kopiuj
USE [mip1]
GO

CREATE NONCLUSTERED INDEX [idx_batch_relation_id] ON [mipadm].[u_tt_batch_relation_mounting_positions_partitioned]
(
    [tt_relation_id] ASC
)
INCLUDE([position]) 
WITH (
    PAD_INDEX = OFF, 
    STATISTICS_NORECOMPUTE = OFF, 
    SORT_IN_TEMPDB = OFF, 
    DROP_EXISTING = OFF, 
    ONLINE = OFF, 
    ALLOW_ROW_LOCKS = ON, 
    ALLOW_PAGE_LOCKS = ON, 
    OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF
)
ON PartitionScheme_Relation_Id([tt_relation_id]);
GO

Mam kilka pytań odnośnie tego co zrobiłem:

  1. Czy całość partycjonowania jest dobrze wykonana? Czy powinienem coś poprawić i ewentalnie co konkretnie?
  2. Jak się ma sprawa z tworzeniem plików, a konkretnie z przydzielaniem dla nich miejsca? Nie do końca rozumiem na jakiej zasadzie sie przypisuje określoną ilość miejsca dla pliku.
  3. Czy można bezpośrednio partycjonować stara tabele, bez tworzenia nowej? Czy wiąże się to z czymś konkretnym? Czy lepiej pozostać, przy tworzeniu nowej tabeli i przenoszeniu danych do niej ze starej tabeli?
  4. Czy można po skonczonym partycjonowaniu, jakiś czas pozniej "dorobić" kolejną partycje, np. dla 800k? Czy lepiej zrobic partycję "do przodu"?
  5. Czy jest możliwosć automatyzacji partycjonowania i w jaki sposób to zrobić? Jakieś zródło najlepiej, zebym sie zapoznał :)

Bardzo dziękuję każdemu za udzieloną odpowiedz.

loza_prowizoryczna
  • Rejestracja:ponad 2 lata
  • Ostatnio:5 dni
  • Postów:1592
0

Partycjonowanie horyzontalne - technika wprowadzona dlatego że silniki baz danych nie są na tyle elastyczne by dać możliwość dodania własnych algorytmów indeksujących a algorytmy ogólne posysają w przypadkach szczególnych. W wyniku tego taki indeks implementujemy po stronie klienta bazy a strukturę samej bazy naginamy pod algorytm. IT w pigułce.


Przetrzyma wszystko
Zobacz pozostałe 4 komentarze
loza_prowizoryczna
To o czym pisze @yarel to bardziej hinting dla bazy (choć silnik powinien robić to sam bazując na profilu użycia i cache). I w sumie to dalej pokazuje że naginamy strukturę pod konkretne zastosowanie bo ogólna baza jest zbyt ogólna. Pytanie konkretniejsze - jak partitioning wpływa na koszt utrzymania spójności danych (bo po to powstały głównie bazy)?
YA
@loza_prowizoryczna: silniki raczej tego nie ogarną w oparciu o profil użycia i cache, a to z tego względu, ze w bloku I/O będzie miał wymieszane dane ( w snsie: w jednym bloku dyskowym będą siedzieć różne wiersze, bądź kolumny (jeśli chcemy iść w columnar storage)). A chcąc mieć dane w tym samym bloku dyskowym? No to właśnie mamy partycjonowanie. Jeśli możesz to rozwiń temat kosztu utrzymania spójności danych przy partycjonowaniu.
loza_prowizoryczna
@yarel: Chodzi mi o to że baza danych ma możność profilowania ważności danych choćby po logowaniu zapytań - więc wie jakich danych klient żąda najwięcej/najczęściej i na podstawie tego powinna odpowiednio je przemieszczać pod spodem. Tak przynajmniej działają dziś tierowe systemy plików.
loza_prowizoryczna
A chcąc mieć dane w tym samym bloku dyskowym - nie do końca rozumiem, chodzi ci o to że masz macierz dyskową, operującą na nim bazę, jedno nie wie o drugim i chcesz mieć możliwość kontroli gdzie baza składuje swoje dane? Tak, wtedy to ma sens - ale to ułomność DB że nie operuje na poziomie bloków tylko na abstrakcji systemu plików.
loza_prowizoryczna
Jeśli możesz to rozwiń temat kosztu utrzymania spójności danych przy partycjonowaniu. - chodzi głównie o składowane procedury i/o klucze. W przypadku jednej tabeli po prostu nakładasz constraint i elo. W przypadku wielu rozproszonych - nie wiem, może widoki też dają takie możliwości choć wątpię.
YA
  • Rejestracja:prawie 10 lat
  • Ostatnio:9 minut
  • Postów:2367
4

@polko13 : Partycjonowanie robi się z jakiegoś powodu, np.:

  • zarządzanie danymi historycznymi (po czasie) - łatwiej wywalić całą partycje niż wybrać rekordy z tabeli i je usunąć, prościej przenieść "stare i rzadko wykorzystywane" dane na wolniejsze dyski
  • usprawnienie zapytań analitycznych, tzw. "partition wise join", gdzie szybciej zrobisz hash joina na mniejszych obiektach (partycjach), niż na tabeli która takich partycji ma dużo (chodzi o to, że partycje często załadujesz w całości do pamięci, a całej tabeli już nie), czy partition purning (pominięcie partycji, które nie są potrzebne do wykonania zapytania)
  • concurrent access - różni użytkownicy mogą pisać po różnych partycjach, które są na różnych dyskach, albo czytać, wówczas zapytanie analityczne może wykonać się efektywniej

Tabela składa się z trzech kolumn tj. id (liczby od 1 i dalej), relation_id (liczby od 1779698 do 682498137) i position (zamienne znaki liter i liczb, np. R3535, które mogą sie powtarzac). Uznałem, że najlepsza do partycjonowania byłaby kolumna relation_id.

Dlaczego najlepsza? Jakie masz zapytania, które mogą skorzystać na partycjonowaniu?

np. select * from tabela where id between 5 and 100; -> partycjonowanie po relation_id nie jest pomocne dla tego zapytania.

YA
  • Rejestracja:prawie 10 lat
  • Ostatnio:9 minut
  • Postów:2367
1

@loza_prowizoryczna kontynuuję tu, bo komentarze za krótkie.

Chodzi mi o to że baza danych ma możność profilowania ważności danych choćby po logowaniu zapytań - więc wie jakich danych klient żąda najwięcej/najczęściej i na podstawie tego powinna odpowiednio je przemieszczać pod spodem. - no ale tu nawet nie musi przemieszczać, te najczęściej używane dane lądują przecież w cache'u, a mniej używane wypadają z cache'a po pewnym czasie. Niektóre silniki mogą zarządzać storage w bardziej wyrafinowany sposób (Oraclowy ASM) i balansować dane na różne urządzenia. Niektóre macierze mają mechanizmy, które rzadko używane dane przenoszą na wolniejsze dyski (dowiedziałem się o tym przypadkiem analizując problem wydajnościowy, gdzie po 30 dniach dane po cichu trafiały na wolniejsze dyski, a 31-go był wykonywany billing za cały miesiąc i było wolno... im dłużej problem był analizowany, tym system szybciej działał :D)

A chcąc mieć dane w tym samym bloku dyskowym - miałem na myśli to, że bez partycjonowania (mowa o tym udostępniamy przez silnik bazy, a nie jakichś samoróbkach w oparciu o widoki i union all - bo to raz, że upierdliwe, a dwa, że optymalizatory zapytań nie zawsze są wstanie wepchnąć predykaty do widoku, albo widoku w widoku w widoku... ) do tego samego bloku dyskowego trafić mogą dane np. za 2012 i 2013 rok. Podczas gdy partycjonowanie po roku zapewniłoby, że do tego samego bloku dyskowego trafią dane z tej samej partycji. W efekcie chcąc dostać dane za 2012 rok, nie musisz czytać nadmiarowej ilości bloków (bo w bloku masz mix 2012 i 2013), a jedynie te bloki, na których jest partycja za 2012. Dzięki temu możesz rozdzielić I/O dla partycji, nie tylko po dyskach, ale i ścieżkach, które do dysków prowadzą (np. osobny interfejs sieciowy, czy osobne porty na switchu, osobna pula dysków na macierzy itd.).

Tej historii o nakładaniu constraintów i składowanych procedura nie rozumiem szczerze powiedziawszy. Nikt (chyba?) przecież nie robi partycjonowania widokami, tylko korzysta z natywnych mechanizmów bazodanowych. Chyba, że zaczynamy łączyć tematykę partycjonowania poziomego, pionowego i shardingu? Ale wówczas byłoby dobrze ustalić kontekst.

loza_prowizoryczna
  • Rejestracja:ponad 2 lata
  • Ostatnio:5 dni
  • Postów:1592
0
yarel napisał(a):
  • no ale tu nawet nie musi przemieszczać, te najczęściej używane dane lądują przecież w cache'u, a mniej używane wypadają z cache'a po pewnym czasie

To jest standard przy tiered storage. Ale jak widzisz ma to swoje ograniczenia - bo to jest system plików a ten ma trochę ciut inną charakterystykę niż baza danych. Dlatego napisałem że ma to sens jeśli jedno nie wie o drugim bo dość łatwo doprowadzić do nieoptymalnego rozłożenia danych (albo nawet zajeżdżenia SSD przy dużych ruchu).

  • Niektóre silniki mogą zarządzać storage w bardziej wyrafinowany sposób (Oraclowy ASM) i balansować dane na różne urządzenia.

No, czyli drogie poczciwe Oracle jednak przygotowało enterprajsowe rozwiązanie w oparciu o wertykalną unifikację. Pytanie czy to produkt wyjątkowy czy konkurencja ma coś podobnego.

A chcąc mieć dane w tym samym bloku dyskowym - miałem na myśli to, że bez partycjonowania (mowa o tym udostępniamy przez silnik bazy, a nie jakichś samoróbkach w oparciu o widoki i union all - bo to raz, że upierdliwe, a dwa, że optymalizatory zapytań nie zawsze są wstanie wepchnąć predykaty do widoku, albo widoku w widoku w widoku... ) do tego samego bloku dyskowego trafić mogą dane np. za 2012 i 2013 rok. Podczas gdy partycjonowanie po roku zapewniłoby, że do tego samego bloku dyskowego trafią dane z tej samej partycji.

Czyli innymi słowy obecnie sposobem na uniknięcie fragmentacji w storage'u bazy jest obecnie dodawanie sztucznych bytów (tabel)? Interesującą drogę w takim razie przebyliśmy od teorii normalizacji ;)

W efekcie chcąc dostać dane za 2012 rok, nie musisz czytać nadmiarowej ilości bloków (bo w bloku masz mix 2012 i 2013), a jedynie te bloki, na których jest partycja za 2012. Dzięki temu możesz rozdzielić I/O dla partycji, nie tylko po dyskach, ale i ścieżkach, które do dysków prowadzą (np. osobny interfejs sieciowy, czy osobne porty na switchu, osobna pula dysków na macierzy itd.).

Nie rozumiem tego czytania nadmiarowych ilości bloków. Ma to jedynie znaczenie gdy:

  • predykat jedzie po kolumnie/kolumnach bez indeksu
  • kolumny te nie mają naturalnego porządku

Tak czy siak wszystko rozbija się o jedno - niemożność dodawania własnych algorytmów indeksujących. Partycjonowanie jako strukturę dla load balancera sobie pominę bo dla mnie to podpada pod samoróbkę ale wyższego rzędu ;)

Tej historii o nakładaniu constraintów i składowanych procedura nie rozumiem szczerze powiedziawszy. Nikt (chyba?) przecież nie robi partycjonowania widokami, tylko korzysta z natywnych mechanizmów bazodanowych. Chyba, że zaczynamy łączyć tematykę partycjonowania poziomego, pionowego i shardingu? Ale wówczas byłoby dobrze ustalić kontekst.

Ustalmy kontekst: moją profesjonalnę przygodę z realnymi DB zakończyłem na InnoDB i hobbystycznych eksperymentach z Postgresem. Obecnie jedyne bazy jakie tykam tylko to sqlite no i na upartego GraphQL. Nie robię na zapleczu i w sumie nie żałuję patrząc gdzie to wszystko podążyło. Jak rozstawałem się z tym tematem to założenia były proste: relacyjne bazy danych były gigantycznymi monolitami opartymi o deklaratywny język do wyciągania danych, był olbrzymi nacisk na normalizację by unikać jak się da redundancji danych + żeby zadeklarowana struktura była jak najbardziej czytelna dla administratora i dała się w miarę prosto obudować procedurami w celu zapewnienia jak najlepszej kontroli nad spójnością danych. Wszystko od storage'u poprzez nawet ukryte indeksy (dodawane w razie potrzeby przez silnik) miało się odbywać pod spodem i być przeźroczyste dla klienta/nawet dla administratora.

Mój komentarz (nawet nie post) dotyczył jedynie tego że zamiast tego ideału z tego co widzę to wszystko podążyło do tego że struktura bazy zamiast odzwierciedlać naturę składowych danych to podążyła w kierunku quasi-optymalizacji dla ułomności silnika co dla ideałów stojących za powstaniem SQL jest praktycznie abominacją :D Oczywiście wszystko wynika pewnie z tego że taniej było postawić jakąś ułomną implementacją MySQL/Postgresa a ułomności wychodzące przy wyższych wolumenach danych łatać ww. technikami.

Koniec rantu, wracam do swojej loży.


Przetrzyma wszystko
YA
  • Rejestracja:prawie 10 lat
  • Ostatnio:9 minut
  • Postów:2367
0

@loza_prowizoryczna

Nie rozumiem tego czytania nadmiarowych ilości bloków.

Może tak, żeby silnik coś zrobił z danymi, to najpierw musi je odczytać, czyli wykonać operację I/O. Nawet jeśli interesuje Cię tylko 1 bit, to minimalny rozmiar takiej operacji I/O wynika z interfejsu urządzenia (np. stare dyski obrotowe - dostajesz cały sektor, 512 bajtów; dyski SSD - 4kb ; +/- to że masz jakieś enterprajzowe ustrojstwa z większym min. rozmiarem I/O), do tego dochodzi page size (rozmiar strony pamięci), czy rozmiar I/O po stronie samej bazy (może preferować czytanie multiblokami - np. dla systemów, które korzystają bardzo z indeksów). Są to różne koncepty, ale powiązane (przez fakt, że dane z dysku trafiają do pamięci procesu). Jeśli w bloku dyskowym upchniesz 10 wierszy z tej samej partycji, to wykonując 1 I/O masz dane o 10 wierszach. Jeśli nie masz partycjonowania, to może się zdarzyć, że te 10 wierszy jest rozsmarowane po 10 blokach dyskowych (-> wykonasz 10x więcej I/O), żeby dostać te 10 wierszy.

Ma to jedynie znaczenie gdy:
predykat jedzie po kolumnie/kolumnach bez indeksu
kolumny te nie mają naturalnego porządku

Nawet jak masz indeks, to musisz go przeczytać, a wtedy lepiej generować mniej I/O niż więcej :) Indeksy mogą być również partycjonowane.
Co do naturalnego porządku, kolumna z wartościami wskazującymi na Kraj. Nie ma naturalnego porządku (ale Polska górą ;) ) i tu jednak widzę różnicę czy w bloku będziemy mieli 10 krajów, czy 10x ten sam kraj.

Co do quasi-optymalizacji to rozdzielenie modelu fizycznego od logicznego chyba było od dawna. Konkurencja dla Oracle, ma też swoje rozwiązania (storage groups, file groups, dynamic tiering).
Ale tak wracając do głównego wątku, to op konkretny case do przećwiczenia. Nie ma mu co hijackować wątku ;-)

loza_prowizoryczna
Może tak, żeby silnik coś zrobił z danymi, to najpierw musi je odczytać, czyli wykonać operację I/O - dlatego indeksy zazwyczaj leżą w osobnym pliku, lookup table powinny być zawsze na levelu z najmniejszymi czasami dostępu, czy to będzie RAM, SSD. Ale nevermind, cała ta dyskusja sprowadza się do tego: bazy danych (poza wymienionymi wyjątkami/wyjątkiem) nie operują bezpośrednio na zapisie blokowym, nie mają pojęcia o storage'u, czy to jest jeden dysk HDD, macierz, czy tierowany pool OpenZFS i vice versa.
loza_prowizoryczna
Nawet jak masz indeks, to musisz go przeczytać, a wtedy lepiej generować mniej I/O niż więcej - indeks się przeszukuje, można go załadować, można go zamapować, kwestia wydajności. kolumna z wartościami wskazującymi na Kraj. Nie ma naturalnego porządku - naturalnego nie ale porządek nie musi być dobry, jeśli zbiór zawiera elementy porównywalne to zawsze istnieje możliwość jego uporządkowania. Konkurencja dla Oracle, ma też swoje rozwiązania - podejrzewam to, cała idea SQL była taka że jest wielu vendorów konkurujących implementacją ale struktura i zapytania są przenośn
loza_prowizoryczna
A tak mamy to co mamy i mamy adminów od DB, techniki denormalizacji i optymalizację struktury pod konkretne zapytania, ech IT w pigułce...
P1
  • Rejestracja:prawie 8 lat
  • Ostatnio:około miesiąc
  • Postów:4
0
yarel napisał(a):

@polko13 : Partycjonowanie robi się z jakiegoś powodu, np.:

  • zarządzanie danymi historycznymi (po czasie) - łatwiej wywalić całą partycje niż wybrać rekordy z tabeli i je usunąć, prościej przenieść "stare i rzadko wykorzystywane" dane na wolniejsze dyski
  • usprawnienie zapytań analitycznych, tzw. "partition wise join", gdzie szybciej zrobisz hash joina na mniejszych obiektach (partycjach), niż na tabeli która takich partycji ma dużo (chodzi o to, że partycje często załadujesz w całości do pamięci, a całej tabeli już nie), czy partition purning (pominięcie partycji, które nie są potrzebne do wykonania zapytania)
  • concurrent access - różni użytkownicy mogą pisać po różnych partycjach, które są na różnych dyskach, albo czytać, wówczas zapytanie analityczne może wykonać się efektywniej

Tabela składa się z trzech kolumn tj. id (liczby od 1 i dalej), relation_id (liczby od 1779698 do 682498137) i position (zamienne znaki liter i liczb, np. R3535, które mogą sie powtarzac). Uznałem, że najlepsza do partycjonowania byłaby kolumna relation_id.

Dlaczego najlepsza? Jakie masz zapytania, które mogą skorzystać na partycjonowaniu?

np. select * from tabela where id between 5 and 100; -> partycjonowanie po relation_id nie jest pomocne dla tego zapytania.

Dziękuję za odpowiedz. Uznałem, że najlepsza, bo:

  1. To zdecydowanie najwieksza tabela w bazie danych w której ucze się/testuje (klon bazy w firmie)
  2. Istnieje procedura, która zbiera dane do różnych tabeli, która następnie wstawia dane do tej tabeli.

Czy jest mi ktoś w stanie konkretnie odpowiedzieć na moje pytania powyżej? Najbardziej zależy mi na informacji, czy to co zrobiłem jest dobrze zrobione. Poprzednio, gdy partycjonowanie tabeli, to partycjonowałem po dacie. Pytania poniżej:

  1. Czy całość partycjonowania jest dobrze wykonana? Czy powinienem coś poprawić i ewentalnie co konkretnie?
  2. Jak się ma sprawa z tworzeniem plików, a konkretnie z przydzielaniem dla nich miejsca? Nie do końca rozumiem na jakiej zasadzie sie przypisuje określoną ilość miejsca dla pliku.
  3. Czy można bezpośrednio partycjonować stara tabele, bez tworzenia nowej? Czy wiąże się to z czymś konkretnym? Czy lepiej pozostać, przy tworzeniu nowej tabeli i przenoszeniu danych do niej ze starej tabeli?
  4. Czy można po skonczonym partycjonowaniu, jakiś czas pozniej "dorobić" kolejną partycje, np. dla 800k? Czy lepiej zrobic partycję "do przodu"?
  5. Czy jest możliwosć automatyzacji partycjonowania i w jaki sposób to zrobić? Jakieś zródło najlepiej, zebym sie zapoznał

Dziękuję za każda udzieloną odpowiedz, jednakżę jestem na takim etapie nauki, ze chciałbym najpierw ten konkretnie aspekt douczyć się, zanim wezmę sie za kolejny. 😀

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)