Projektowanie tabel przy użyciu usługi Synapse SQL w usłudze Azure Synapse Analytics

Ten dokument zawiera kluczowe pojęcia dotyczące projektowania tabel z dedykowaną pulą SQL i bezserwerową pulą SQL.

Bezserwerowa pula SQL to usługa zapytań dla danych w usłudze Data Lake. Nie ma magazynu lokalnego na potrzeby pozyskiwania danych. Dedykowana pula SQL reprezentuje kolekcję zasobów analitycznych, które są aprowizowane podczas korzystania z usługi Synapse SQL. Rozmiar dedykowanej puli SQL jest określany przez jednostki magazynowania danych (DWU).

W poniższej tabeli wymieniono tematy dotyczące dedykowanej puli SQL a bezserwerowej puli SQL:

Temat dedykowana pula SQL Bezserwerowa pula SQL
Określanie kategorii tabel Tak Nie
Nazwy schematów Tak Tak
Nazwy tabel Tak Nie
Trwałość tabeli Tak Nie
Zwykła tabela Tak Nie
Tabela tymczasowa Tak Tak
Tabela zewnętrzna Tak Tak
Typy danych Tak Tak
Rozproszone tabele Tak Nie
Tabele dystrybuowane przy użyciu skrótu Tak Nie
Zreplikowane tabele Tak Nie
Tabele działania okrężnego Tak Nie
Typowe metody dystrybucji tabel Tak Nie
Partycji Tak Tak
Indeksy magazynu kolumn Tak Nie
Statystyki Tak Tak
Klucz podstawowy i unikatowy klucz Tak Nie
Polecenia służące do tworzenia tabel Tak Nie
Dopasowywanie danych źródłowych do magazynu danych Tak Nie
Nieobsługiwane funkcje tabeli Tak Nie
Zapytania dotyczące rozmiaru tabeli Tak Nie

Określanie kategorii tabel

Schemat gwiazdy organizuje dane w tabelach faktów i wymiarów. Niektóre tabele są używane do integracji lub przemieszczania danych przed przejściem do tabeli faktów lub wymiarów. Podczas projektowania tabeli zdecyduj, czy dane tabeli należą do tabeli faktów, wymiarów czy tabeli integracji. Ta decyzja informuje o odpowiedniej strukturze tabeli i dystrybucji.

  • Tabele faktów zawierają dane ilościowe, które są często generowane w systemie transakcyjnym, a następnie ładowane do magazynu danych. Na przykład firma detaliczna generuje transakcje sprzedaży codziennie, a następnie ładuje dane do tabeli faktów magazynu danych na potrzeby analizy.

  • Tabele wymiarów zawierają dane atrybutów, które mogą ulec zmianie, ale zwykle zmieniają się rzadko. Na przykład nazwa i adres klienta są przechowywane w tabeli wymiarów i aktualizowane tylko wtedy, gdy profil klienta ulegnie zmianie. Aby zminimalizować rozmiar dużej tabeli faktów, nazwa i adres klienta nie muszą znajdować się w każdym wierszu tabeli faktów. Zamiast tego tabela faktów i tabela wymiarów mogą udostępniać identyfikator klienta. Zapytanie może łączyć dwie tabele w celu skojarzenia profilu i transakcji klienta.

  • Tabele integracji zapewniają miejsce na integrowanie lub przemieszczanie danych. Tabelę integracji można utworzyć jako zwykłą tabelę, tabelę zewnętrzną lub tabelę tymczasową. Na przykład można załadować dane do tabeli przejściowej, wykonać przekształcenia na danych w środowisku przejściowym, a następnie wstawić dane do tabeli produkcyjnej.

Nazwy schematów

Schematy są dobrym sposobem grupowania obiektów, które są używane w podobny sposób. Poniższy kod tworzy schemat zdefiniowany przez użytkownika o nazwie wwi.

CREATE SCHEMA wwi;

Nazwy tabel

Jeśli migrujesz wiele baz danych z lokalnego rozwiązania do dedykowanej puli SQL, najlepszym rozwiązaniem jest migrowanie wszystkich tabel faktów, wymiarów i integracji do jednego schematu puli SQL. Na przykład można przechowywać wszystkie tabele w przykładowym magazynie danych WideWorldImportersDW w jednym schemacie o nazwie wwi.

Aby pokazać organizację tabel w dedykowanej puli SQL, można użyć faktów, dim i int jako prefiksów do nazw tabel. W poniższej tabeli przedstawiono niektóre nazwy schematów i tabel wideworldImportersDW.

Tabela WideWorldImportersDW Typ tabeli dedykowana pula SQL
City (Miasto) Wymiar Wwi. DimCity
Zamówienie Fact Wwi. FactOrder

Trwałość tabeli

Tabele przechowują dane trwale w usłudze Azure Storage, tymczasowo w usłudze Azure Storage lub w magazynie danych zewnętrznym dla magazynu danych.

Zwykła tabela

Zwykła tabela przechowuje dane w usłudze Azure Storage w ramach magazynu danych. Tabela i dane są utrwalane bez względu na to, czy sesja jest otwarta. Poniższy przykład tworzy zwykłą tabelę z dwiema kolumnami.

CREATE TABLE MyTable (col1 int, col2 int );  

Tabela tymczasowa

Tabela tymczasowa istnieje tylko przez czas trwania sesji. Możesz użyć tabeli tymczasowej, aby uniemożliwić innym użytkownikom wyświetlanie tymczasowych wyników. Korzystanie z tabel tymczasowych zmniejsza również potrzebę czyszczenia. Tabele tymczasowe korzystają z magazynu lokalnego i, w dedykowanych pulach SQL, mogą oferować szybszą wydajność.

Bezserwerowa pula SQL obsługuje tabele tymczasowe. Jednak jego użycie jest ograniczone, ponieważ można wybrać z tabeli tymczasowej, ale nie można połączyć jej z plikami w magazynie.

Aby uzyskać więcej informacji, zobacz Tabele tymczasowe.

Tabela zewnętrzna

Tabele zewnętrzne wskazują dane znajdujące się w obiekcie blob usługi Azure Storage lub Azure Data Lake Storage.

Zaimportuj dane z tabel zewnętrznych do dedykowanych pul SQL przy użyciu instrukcji CREATE TABLE AS SELECT . Aby zapoznać się z samouczkiem dotyczącym ładowania, zobacz Ładowanie danych z usługi Azure Blob Storage przy użyciu technologii PolyBase.

W przypadku bezserwerowej puli SQL można użyć instrukcji CETAS , aby zapisać wynik zapytania w tabeli zewnętrznej w usłudze Azure Storage.

Typy danych

Dedykowana pula SQL obsługuje najczęściej używane typy danych. Aby uzyskać listę obsługiwanych typów danych, zobacz typy danych w dokumentacji CREATE TABLE w instrukcji CREATE TABLE. Aby uzyskać więcej informacji na temat używania typów danych, zobacz Typy danych.

Rozproszone tabele

Podstawową funkcją dedykowanej puli SQL jest sposób przechowywania i obsługi tabel w różnych dystrybucjach. Dedykowana pula SQL obsługuje trzy metody dystrybucji danych:

  • Działanie okrężne (ustawienie domyślne)
  • Skrót
  • Replikowane

Tabele dystrybuowane przy użyciu skrótu

Tabela rozproszona skrótu dystrybuuje wiersze na podstawie wartości w kolumnie dystrybucji. Tabela rozproszona skrótu została zaprojektowana w celu osiągnięcia wysokiej wydajności zapytań w dużych tabelach. Podczas wybierania kolumny dystrybucji należy wziąć pod uwagę kilka czynników.

Aby uzyskać więcej informacji, zobacz Wskazówki dotyczące projektowania tabel rozproszonych.

Zreplikowane tabele

Replikowana tabela zawiera pełną kopię tabeli dostępnej w każdym węźle obliczeniowym. Zapytania działają szybko w replikowanych tabelach, ponieważ sprzężenia w replikowanych tabelach nie wymagają przenoszenia danych. Jednak replikacja wymaga dodatkowego magazynu i nie jest praktyczna w przypadku dużych tabel.

Aby uzyskać więcej informacji, zobacz Wskazówki dotyczące projektowania replikowanych tabel.

Tabele działania okrężnego

Tabela okrężna dystrybuuje wiersze tabeli równomiernie we wszystkich dystrybucjach. Wiersze są dystrybuowane losowo. Ładowanie danych do tabeli działania okrężnego jest szybkie. Jednak zapytania mogą wymagać większego przenoszenia danych niż inne metody dystrybucji.

Aby uzyskać więcej informacji, zobacz Wskazówki dotyczące projektowania tabel rozproszonych.

Typowe metody dystrybucji tabel

Kategoria tabeli często określa optymalną opcję rozkładu tabel.

Kategoria tabeli Zalecana opcja dystrybucji
Fact Użyj dystrybucji skrótów z klastrowanym indeksem magazynu kolumn. Wydajność zwiększa się, gdy dwie tabele skrótów są sprzężone w tej samej kolumnie dystrybucji.
Wymiar Użyj replikowanej dla mniejszych tabel. Jeśli tabele są zbyt duże do przechowywania w każdym węźle obliczeniowym, użyj skrótu rozproszonego.
Przygotowanie Użyj działania okrężnego dla tabeli przejściowej. Ładowanie za pomocą usługi CTAS jest szybkie. Gdy dane są w tabeli przejściowej, użyj polecenia INSERT... WYBIERZ, aby przenieść dane do tabel produkcyjnych.

Partycje

W dedykowanych pulach SQL partycjonowana tabela przechowuje i wykonuje operacje na wierszach tabeli zgodnie z zakresami danych. Na przykład tabela może być partycjonowana według dnia, miesiąca lub roku. Wydajność zapytań można poprawić poprzez eliminację partycji, co ogranicza skanowanie zapytań do danych w ramach partycji.

Dane można również przechowywać za pomocą przełączania partycji. Ponieważ dane w dedykowanej puli SQL są już dystrybuowane, zbyt wiele partycji może spowolnić wydajność zapytań. Aby uzyskać więcej informacji, zobacz Partitioning guidance (Wskazówki dotyczące partycjonowania).

Porada

Podczas przełączania partycji na partycje tabeli, które nie są puste, rozważ użycie opcji TRUNCATE_TARGET w instrukcji ALTER TABLE , jeśli istniejące dane mają zostać obcięte.

Poniższy kod przełącza przekształcone dane dzienne na partycję SalesFact i zastępuje wszystkie istniejące dane.

ALTER TABLE SalesFact_DailyFinalLoad SWITCH PARTITION 256 TO SalesFact PARTITION 256 WITH (TRUNCATE_TARGET = ON);  

W bezserwerowej puli SQL można ograniczyć pliki/foldery (partycje), które będą odczytywane przez zapytanie. Partycjonowanie według ścieżki jest obsługiwane przy użyciu funkcji filepath i fileinfo opisanych w artykule Wykonywanie zapytań dotyczących plików magazynu. Poniższy przykład odczytuje folder z danymi w roku 2017:

SELECT
    nyc.filepath(1) AS [year],
    payment_type,
    SUM(fare_amount) AS fare_total
FROM  
    OPENROWSET(
        BULK 'https://sqlondemandstorage.blob.core.windows.net/parquet/taxi/year=*/month=*/*.parquet',
        FORMAT='PARQUET'
    ) AS nyc
WHERE
    nyc.filepath(1) = 2017
GROUP BY
    nyc.filepath(1),
    payment_type
ORDER BY
    nyc.filepath(1),
    payment_type

Indeksy magazynu kolumn

Domyślnie dedykowana pula SQL przechowuje tabelę jako indeks klastrowanego magazynu kolumn. Ta forma magazynu danych zapewnia wysoką kompresję danych i wydajność zapytań w dużych tabelach. Indeks klastrowanego magazynu kolumn jest zwykle najlepszym wyborem, ale w niektórych przypadkach indeks klastrowany lub stertę jest odpowiednią strukturą magazynu.

Porada

Tabela sterty może być szczególnie przydatna do ładowania danych przejściowych, takich jak tabela przejściowa, która jest przekształcana w końcową tabelę.

Aby uzyskać listę funkcji magazynu kolumn, zobacz Co nowego dla indeksów magazynu kolumn. Aby zwiększyć wydajność indeksu magazynu kolumn, zobacz Maksymalizowanie jakości grup wierszy dla indeksów magazynu kolumn.

Statystyki

Optymalizator zapytań używa statystyk na poziomie kolumny podczas tworzenia planu do wykonywania zapytania. Aby zwiększyć wydajność zapytań, ważne jest, aby statystyki dotyczące poszczególnych kolumn, zwłaszcza kolumn używanych w sprzężeniach zapytań. Usługa Synapse SQL obsługuje automatyczne tworzenie statystyk.

Aktualizacja statystyczna nie jest automatycznie aktualizowana. Zaktualizuj statystyki po dodaniu lub zmianie liczby wierszy. Na przykład zaktualizuj statystyki po załadowaniu. Dodatkowe informacje znajdują się w artykule Wskazówki dotyczące statystyk .

Klucz podstawowy i unikatowy klucz

W przypadku dedykowanej puli SQL klucz PODSTAWOWY jest obsługiwany tylko wtedy, gdy są używane zarówno elementy NONCLUSTERED, jak i NOT ENFORCED. Ograniczenie UNIQUE jest obsługiwane tylko wtedy, gdy nie jest używana wartość WYMUSZAna. Aby uzyskać więcej informacji, zobacz dedykowany artykuł dotyczący ograniczeń tabeli puli SQL .

Polecenia służące do tworzenia tabel

W przypadku dedykowanej puli SQL można utworzyć tabelę jako nową pustą tabelę. Możesz również utworzyć i wypełnić tabelę wynikami instrukcji select. Poniżej przedstawiono polecenia języka T-SQL służące do tworzenia tabeli.

T-SQL, instrukcja Opis
CREATE TABLE Tworzy pustą tabelę, definiując wszystkie kolumny i opcje tabeli.
TWORZENIE TABELI ZEWNĘTRZNEJ Tworzy tabelę zewnętrzną. Definicja tabeli jest przechowywana w dedykowanej puli SQL. Dane tabeli są przechowywane w usłudze Azure Blob Storage lub Azure Data Lake Storage.
CREATE TABLE AS SELECT Wypełnia nową tabelę wynikami instrukcji select. Kolumny tabeli i typy danych są oparte na wynikach instrukcji select. Aby zaimportować dane, ta instrukcja może wybrać z tabeli zewnętrznej.
UTWÓRZ TABELĘ ZEWNĘTRZNĄ JAKO WYBIERZ Tworzy nową tabelę zewnętrzną przez wyeksportowanie wyników instrukcji select do lokalizacji zewnętrznej. Lokalizacja to usługa Azure Blob Storage lub Azure Data Lake Storage.

Dopasowywanie danych źródłowych do magazynu danych

Dedykowane tabele puli SQL są wypełniane przez ładowanie danych z innego źródła danych. Aby osiągnąć pomyślne ładowanie, liczba i typy danych kolumn w danych źródłowych muszą być zgodne z definicją tabeli w magazynie danych.

Uwaga

Pobieranie danych do wyrównania może być najtrudniejszą częścią projektowania tabel.

Jeśli dane pochodzą z wielu magazynów danych, możesz przenieść dane do magazynu danych i zapisać je w tabeli integracji. Gdy dane są w tabeli integracji, możesz użyć możliwości dedykowanej puli SQL do zaimplementowania operacji przekształcania. Po przygotowaniu danych można je wstawić do tabel produkcyjnych.

Nieobsługiwane funkcje tabeli

Dedykowana pula SQL obsługuje wiele funkcji tabeli oferowanych przez inne bazy danych, ale nie wszystkie. Poniższa lista zawiera niektóre funkcje tabeli, które nie są obsługiwane w dedykowanej puli SQL.

Zapytania dotyczące rozmiaru tabeli

W dedykowanej puli SQL jednym z prostych sposobów identyfikowania miejsca i wierszy używanych przez tabelę w każdej z 60 dystrybucji jest użycie PDW_SHOWSPACEUSED DBCC.

DBCC PDW_SHOWSPACEUSED('dbo.FactInternetSales');

Należy pamiętać, że używanie poleceń DBCC może być dość ograniczane. Dynamiczne widoki zarządzania (DMV) pokazują więcej szczegółów niż polecenia DBCC. Zacznij od utworzenia poniższego widoku.

CREATE VIEW dbo.vTableSizes
AS
WITH base
AS
(
SELECT
 GETDATE()                                                             AS  [execution_time]
, DB_NAME()                                                            AS  [database_name]
, s.name                                                               AS  [schema_name]
, t.name                                                               AS  [table_name]
, QUOTENAME(s.name)+'.'+QUOTENAME(t.name)                              AS  [two_part_name]
, nt.[name]                                                            AS  [node_table_name]
, ROW_NUMBER() OVER(PARTITION BY nt.[name] ORDER BY (SELECT NULL))     AS  [node_table_name_seq]
, tp.[distribution_policy_desc]                                        AS  [distribution_policy_name]
, c.[name]                                                             AS  [distribution_column]
, nt.[distribution_id]                                                 AS  [distribution_id]
, i.[type]                                                             AS  [index_type]
, i.[type_desc]                                                        AS  [index_type_desc]
, nt.[pdw_node_id]                                                     AS  [pdw_node_id]
, pn.[type]                                                            AS  [pdw_node_type]
, pn.[name]                                                            AS  [pdw_node_name]
, di.name                                                              AS  [dist_name]
, di.position                                                          AS  [dist_position]
, nps.[partition_number]                                               AS  [partition_nmbr]
, nps.[reserved_page_count]                                            AS  [reserved_space_page_count]
, nps.[reserved_page_count] - nps.[used_page_count]                    AS  [unused_space_page_count]
, nps.[in_row_data_page_count]
    + nps.[row_overflow_used_page_count]
    + nps.[lob_used_page_count]                                        AS  [data_space_page_count]
, nps.[reserved_page_count]
 - (nps.[reserved_page_count] - nps.[used_page_count])
 - ([in_row_data_page_count]
         + [row_overflow_used_page_count]+[lob_used_page_count])       AS  [index_space_page_count]
, nps.[row_count]                                                      AS  [row_count]
from
    sys.schemas s
INNER JOIN sys.tables t
    ON s.[schema_id] = t.[schema_id]
INNER JOIN sys.indexes i
    ON  t.[object_id] = i.[object_id]
    AND i.[index_id] <= 1
INNER JOIN sys.pdw_table_distribution_properties tp
    ON t.[object_id] = tp.[object_id]
INNER JOIN sys.pdw_table_mappings tm
    ON t.[object_id] = tm.[object_id]
INNER JOIN sys.pdw_nodes_tables nt
    ON tm.[physical_name] = nt.[name]
INNER JOIN sys.dm_pdw_nodes pn
    ON  nt.[pdw_node_id] = pn.[pdw_node_id]
INNER JOIN sys.pdw_distributions di
    ON  nt.[distribution_id] = di.[distribution_id]
INNER JOIN sys.dm_pdw_nodes_db_partition_stats nps
    ON nt.[object_id] = nps.[object_id]
    AND nt.[pdw_node_id] = nps.[pdw_node_id]
    AND nt.[distribution_id] = nps.[distribution_id]
LEFT OUTER JOIN (select * from sys.pdw_column_distribution_properties where distribution_ordinal = 1) cdp
    ON t.[object_id] = cdp.[object_id]
LEFT OUTER JOIN sys.columns c
    ON cdp.[object_id] = c.[object_id]
    AND cdp.[column_id] = c.[column_id]
WHERE pn.[type] = 'COMPUTE'
)
, size
AS
(
SELECT
   [execution_time]
,  [database_name]
,  [schema_name]
,  [table_name]
,  [two_part_name]
,  [node_table_name]
,  [node_table_name_seq]
,  [distribution_policy_name]
,  [distribution_column]
,  [distribution_id]
,  [index_type]
,  [index_type_desc]
,  [pdw_node_id]
,  [pdw_node_type]
,  [pdw_node_name]
,  [dist_name]
,  [dist_position]
,  [partition_nmbr]
,  [reserved_space_page_count]
,  [unused_space_page_count]
,  [data_space_page_count]
,  [index_space_page_count]
,  [row_count]
,  ([reserved_space_page_count] * 8.0)                                 AS [reserved_space_KB]
,  ([reserved_space_page_count] * 8.0)/1000                            AS [reserved_space_MB]
,  ([reserved_space_page_count] * 8.0)/1000000                         AS [reserved_space_GB]
,  ([reserved_space_page_count] * 8.0)/1000000000                      AS [reserved_space_TB]
,  ([unused_space_page_count]   * 8.0)                                 AS [unused_space_KB]
,  ([unused_space_page_count]   * 8.0)/1000                            AS [unused_space_MB]
,  ([unused_space_page_count]   * 8.0)/1000000                         AS [unused_space_GB]
,  ([unused_space_page_count]   * 8.0)/1000000000                      AS [unused_space_TB]
,  ([data_space_page_count]     * 8.0)                                 AS [data_space_KB]
,  ([data_space_page_count]     * 8.0)/1000                            AS [data_space_MB]
,  ([data_space_page_count]     * 8.0)/1000000                         AS [data_space_GB]
,  ([data_space_page_count]     * 8.0)/1000000000                      AS [data_space_TB]
,  ([index_space_page_count]  * 8.0)                                   AS [index_space_KB]
,  ([index_space_page_count]  * 8.0)/1000                              AS [index_space_MB]
,  ([index_space_page_count]  * 8.0)/1000000                           AS [index_space_GB]
,  ([index_space_page_count]  * 8.0)/1000000000                        AS [index_space_TB]
FROM base
)
SELECT *
FROM size
;

Podsumowanie obszaru tabeli

To zapytanie zwraca wiersze i spację według tabeli. Podsumowanie obszaru tabeli pozwala zobaczyć, które tabele są największymi tabelami. Zobaczysz również, czy są one działaniem okrężnym, replikowanym, czy rozproszonym skrótem. W przypadku tabel rozproszonych skrótami zapytanie wyświetla kolumnę dystrybucji.

SELECT
     database_name
,    schema_name
,    table_name
,    distribution_policy_name
,      distribution_column
,    index_type_desc
,    COUNT(distinct partition_nmbr) as nbr_partitions
,    SUM(row_count)                 as table_row_count
,    SUM(reserved_space_GB)         as table_reserved_space_GB
,    SUM(data_space_GB)             as table_data_space_GB
,    SUM(index_space_GB)            as table_index_space_GB
,    SUM(unused_space_GB)           as table_unused_space_GB
FROM
    dbo.vTableSizes
GROUP BY
     database_name
,    schema_name
,    table_name
,    distribution_policy_name
,      distribution_column
,    index_type_desc
ORDER BY
    table_reserved_space_GB desc
;

Odstęp tabeli według typu dystrybucji

SELECT
     distribution_policy_name
,    SUM(row_count)                as table_type_row_count
,    SUM(reserved_space_GB)        as table_type_reserved_space_GB
,    SUM(data_space_GB)            as table_type_data_space_GB
,    SUM(index_space_GB)           as table_type_index_space_GB
,    SUM(unused_space_GB)          as table_type_unused_space_GB
FROM dbo.vTableSizes
GROUP BY distribution_policy_name
;

Obszar tabeli według typu indeksu

SELECT
     index_type_desc
,    SUM(row_count)                as table_type_row_count
,    SUM(reserved_space_GB)        as table_type_reserved_space_GB
,    SUM(data_space_GB)            as table_type_data_space_GB
,    SUM(index_space_GB)           as table_type_index_space_GB
,    SUM(unused_space_GB)          as table_type_unused_space_GB
FROM dbo.vTableSizes
GROUP BY index_type_desc
;

Podsumowanie obszaru dystrybucji

SELECT
    distribution_id
,    SUM(row_count)                as total_node_distribution_row_count
,    SUM(reserved_space_MB)        as total_node_distribution_reserved_space_MB
,    SUM(data_space_MB)            as total_node_distribution_data_space_MB
,    SUM(index_space_MB)           as total_node_distribution_index_space_MB
,    SUM(unused_space_MB)          as total_node_distribution_unused_space_MB
FROM dbo.vTableSizes
GROUP BY     distribution_id
ORDER BY    distribution_id
;

Następne kroki

Po utworzeniu tabel dla magazynu danych następnym krokiem jest załadowanie danych do tabeli. Aby zapoznać się z samouczkiem dotyczącym ładowania, zobacz Ładowanie danych do dedykowanej puli SQL.