

Zastrzeżenie: opinia w tym artykule jest tylko moja, w oparciu o moją ograniczoną ekspozycję na wykres SQL Server. Nie jestem w żaden sposób ekspertem od SQL Server. Mogę być stronniczy w stosunku do Neo4j.
wraz z rosnącym wykorzystaniem bazy danych Graph i dominacją Neo4j na tym niszowym rynku,a także znaczącym wzrostem wydajności w wyszukiwaniu silnie powiązanych danych, jest zrozumiałe, że Microsoft nie chce zostać pominięty w tym mega-trendzie.
począwszy od SQL Server 2017, SQL Server oferował funkcje Wykresów, wraz z wprowadzeniem słowa kluczowegoMATCH
. W wersji 2019 dodano m.in. dwie nowe, godne uwagi funkcje: ograniczenia krawędzi oraz wykorzystanie tabel pochodnych w zapytaniach MATCH
. Nurkowanie w tej technologii wystarczająco długo, mam wrażenie, że na razie:
- obsługa Wykresów w SQL Server jest nadal daleka od pełnej bazy Wykresów, np. Neo4j.
- dodawanie funkcjonalności jest powoli przyrostowe.
- funkcja grafu jest wbudowana w relacyjną bazę danych.
przejdźmy do szczegółów!
plusy& minusy
słowo kluczowe MATCH
jest moim zdaniem jedynie cukrem składniowym. Zamiast:
SELECT *
FROM NodeTable1 nt1 JOIN EdgeTable et ON nt1.$node_id = et.$from_id JOIN NodeTable2 nt2 ON nt2.$node_id = et.$to_id
… użytkownicy mogą dość dużo skrócić zapytanie jako:
SELECT *
FROM NodeTable1 nt1, EdgeTable et, NodeTable2 nt2
WHERE MATCH(nt1-(et)->nt2)
skrócone zapytanie jest niewątpliwie przyjemne dla oczu. Jednak w. Net world Entity Framework może być preferowany dla aplikacji zorientowanych na dane; w wyniku czego nie ma potrzeby stosowania poleceń tekstowych SQL. Programiści po prostu pozwalają frameworkowi generować dla nich optymalne zapytania, podczas gdy koncentrują się na abstrakcjach wysokiego poziomu. Zgodnie z tą logiką, przyjemny efekt MATCH
jest nagle nieistotny. Co gorsza, w tej chwili nie ma nawet mapy drogowej wspierającej te możliwości Wykresów w Entity Framework (Core).
porównując do Neo4j, patrząc ponownie na powyższe zapytania, nieuniknione jest, aby użytkownicy naginali swoje myślenie Wykresów w relacyjny świat baz danych. Musimy jeszcze z góry zadeklarować, które tabele, w klauzuli FROM
, mają przeprowadzić dopasowanie (czy powinien to być raczej Wykres uważany za „całość przejezdną” i nie trzeba dbać o szczegółową organizację danych?). Gdy znajomość kierunku strzałki w MATCH
jest koniecznością, użytkownicy zdają sobie sprawę z mapowania 1-1 między MATCH
klauzulą a oryginalną klauzulą JOIN
, w tym sensie, że trzeba odróżnić węzeł źródłowy od węzła docelowego. Natomiast składnia szyfrowa Neo4j pozwala zignorować to rozróżnienie. Wszystko to niekoniecznie zmienia zasady gry, ale jest po prostu kwestią wygody i radości z rozwoju. (Później, w pierwszym przypadku badania, zobaczymy, że musimy zrobić UNION ALL
z tego powodu.)
jednym z kluczy do wysokiej wydajności natywnej bazy danych grafów w przeszukiwaniu połączonych danych jest przyleganie bez indeksów. Niestety w SQL Server nie ma czegoś takiego z funkcją Graph:
nie utrzymujemy listy adjacency na każdym węźle; zamiast tego przechowujemy dane krawędzi w tabelach. Ponieważ jest to relacyjna baza danych, przechowywanie danych w formie tabel było dla nas bardziej naturalnym wyborem
kolejnym irytującym problemem jest brak narzędzi do wizualizacji dostosowanych do grafu, zarówno dla schematu, jak i danych. Jako obejście, użytkownicy mogą nadal tworzyć schemat w SSMS, ale te tabele węzłów i krawędzi kończą się jako pojedyncze, rozłączone tabele, nawet jeśli mają ograniczenia krawędzi. Między innymi Technologia graficzna powinna również przynosić odwołania wizualne, ułatwiając użytkownikom konstruowanie prawidłowych zapytań. Brak takich narzędzi jest frustrujący i niekorzystny dla produktywności programistów.

więc co zrobić, aby uzyskać schemat wykresu? Myślę, że otwieramy każdą tabelę krawędzi, aby ręcznie zobaczyć ograniczenia, a następnie, za pomocą kartki papieru, odczytać cały schemat wykresu.

jeśli chodzi o wizualizację danych, próbowałem Microsoft Power BI Z Force-Directed graph addon. Jednak to narzędzie nie jest darmowe i nie obsługuje możliwości Wykresów SQL Server od razu, co oznacza, że widzi tabele węzłów i krawędzi jako normalne tabele bazy danych. Przyglądając się dokładnie listom kolumn, pojawiają się dziwnie wyglądające nazwy kolumn, np. graph_id_...
,from_obj_id...
. Są to kolumny wewnętrzne, generowane automatycznie podczas tworzenia tabel węzłów / krawędzi, niedostępne z zewnątrz. Błąd jest podnoszony, jak poniżej, przez funkcję pobierania danych Power BI, jeśli uzyskujesz dostęp do tych kolumn.

aby obejść ten problem, należy utworzyć widok bazy danych zawierający tylko odpowiednie/osiągalne kolumny, np. from_id
i to_id
w tabeli krawędzi, node_id
w tabeli węzłów. Następnie w usłudze Power BI wyodrębnij dane za pomocą tego widoku. Mam nadzieję, że się nie mylę, Wykres Power BI w kierunku siły wydaje się wymagać jednej tabeli, która składa się z kolumn Source
, Target
, Weight
, Source Type
, Target Type
, Link Type
. Nasz przykładowy schemat jest uproszczony, dlatego tworzenie tej pojedynczej tabeli jest trywialne. Co jeśli schemat zawierał tabele + 20 węzłów i tabelę + 10 krawędzi, czy moglibyśmy skończyć z pojedynczą tabelą, aby wizualizować cały Wykres za pomocą Power BI?
#Zaktualizowano 04.07.2020: Po namyśle, jest to z pewnością możliwe, nawet jeśli jest to nadal uciążliwe. Należy zacząć od tabel krawędzi, w każdej z nich $from_id
i $to_id
są połączone z odpowiednimi tabelami węzłów, aby przetłumaczyć je na współdzielone właściwości wszystkich węzłów, np. Name
lub Id
. Następnie wykonaj UNION ALL
dla wszystkich, aby połączyć się w finałowym pojedynczym stole wymaganym przez Power BI.
Zapytanie o węzły i krawędzie jest jedną z możliwości technologii grafów. To, co może wyróżniać bazę danych grafów, to wbudowana, ale rozszerzalna obsługa algorytmów grafów, takich jak PageRank i Louvain Community Detection (aka. Modułowość Louvain). Niestety ponownie, nie ma takich funkcji analitycznych dostępnych w wykresie SQL Server, jak powiedział:
niektóre bazy danych grafów zapewniają dedykowane funkcje analizy grafów, takie jak „najkrótsza ścieżka” lub ” page rank.”SQL Graph nie udostępnia żadnych takich funkcji w tym wydaniu. Ponownie, pętle T-SQL i tabele temp mogą być użyte do napisania obejścia tych scenariuszy.
w Neo4j algorytmy te są łatwo dostępne na poziomie produkcyjnym, dzięki bibliotece Graph Data Science Library. Plus, jest open-source. Ogólnie rzecz biorąc, dokumentacja jest pomocna, ale czasami niewystarczająca. Dzięki oprogramowaniu open-source programiści mogą pobierać i analizować sposób implementacji określonego algorytmu; a nawet przekompilować bibliotekę z dodatkowymi informacjami o logowaniu, aby lepiej zrozumieć. Implementacja PageRank w SQL jest możliwa, ale bardziej złożony algorytm, taki jak modułowość Louvain, może być wyzwaniem. Niemniej jednak wielu inżynierów oprogramowania woli bardziej przejmować się logiką biznesową, zamiast ugrzęzać w niskopoziomowych szczegółach technicznych.
wreszcie, moim zdaniem, wyrażenie Common Table jest rodzajem tabel pochodnych. Od SQL Server 2019 technika ta oficjalnie ma być wykonalna z grafem:

ale jeśli po utworzeniu widoku, jest to do-able:

myślę, że jest to oznaka niespójności. Drugie podejście wymaga permanentnie utworzonego widoku, ponieważ nie jest możliwe utworzenie tymczasowego widoku w SQL Server. Zwykle użytkownicy pokonują to za pomocą CTE, ale znowu CTE nie działa z grafem, jak pokazano powyżej.
przypadki studiowania
przykładowy scenariusz: uczniowie i nauczyciele.

Cypher Neo4j:
CREATE (S1:NStudents {name: "S1"}), (S2:NStudents {name: "S2"}), (T1:NTeachers {name: "T1"}), (S3:NStudents {name: "S3"}), (T2:NTeachers {name: "T2"}), (S4:NStudents {name: "S4"}), (S1)-->(S2), (S2)-->(T1), (T1)-->(T2), (T2)-->(S4), (S3)-->(T1)
Wykres SQL Server 2019:
CREATE TABLE NStudents ( NVARCHAR(MAX) NOT NULL, INT NOT NULL) AS NODE;CREATE TABLE NTeachers ( NVARCHAR(MAX) NOT NULL, FLOAT NOT NULL) AS NODE;CREATE TABLE Talks (CONSTRAINT EC_Talk CONNECTION (NStudents TO NStudents, NStudents TO NTeachers, NTeachers TO NStudents, NTeachers TO NTeachers) ON DELETE CASCADE) AS EDGE;INSERT INTO NStudents VALUES ('S1',1),('S2',2),('S3',3),('S4',4);
INSERT INTO NTeachers VALUES ('T1',123), ('T2',456);
INSERT INTO Talks VALUES (
(SELECT $node_id FROM NStudents WHERE = 'S1'),
(SELECT $node_id FROM NStudents WHERE = 'S2'));
INSERT INTO Talks VALUES (
(SELECT $node_id FROM NStudents WHERE = 'S2'),
(SELECT $node_id FROM NTeachers WHERE = 'T1'));
INSERT INTO Talks VALUES (
(SELECT $node_id FROM NTeachers WHERE = 'T1'),
(SELECT $node_id FROM NTeachers WHERE = 'T2'));
INSERT INTO Talks VALUES (
(SELECT $node_id FROM NTeachers WHERE = 'T2'),
(SELECT $node_id FROM NStudents WHERE = 'S4'));
INSERT INTO Talks VALUES (
(SELECT $node_id FROM NStudents WHERE = 'S3'),
(SELECT $node_id FROM NTeachers WHERE = 'T1'));
Przypadek 1: Wszystkie połączenia przychodzące i wychodzące węzłów
motywacja: liczenie tych połączeń dla każdego węzła jest jednym ze sposobów, aby dowiedzieć się, które z nich są najważniejsze.
Neo4j ’ scypher:
MATCH (n)--()
RETURN n.name, COUNT(r) AS allCons
ORDER BY allCons DESC

Wykres SQL Server 2019:
--Create a View first, for convenience purpose.
CREATE VIEW view_AllPeople
AS
SELECT $node_id AS ,
FROM NStudents
UNION ALL
SELECT $node_id AS ,
FROM NTeachers;--Query using the View.
WITH CTE()
AS
(
SELECT ap1.
FROM view_AllPeople ap1, Talks t, view_AllPeople ap2
WHERE MATCH(ap1-(t)->ap2)
UNION ALL
SELECT ap1.
FROM view_AllPeople ap1, Talks t, view_AllPeople ap2
WHERE MATCH(ap1<-(t)-ap2)
)
SELECT , COUNT(*) AS allConns
FROM CTE
GROUP BY
ORDER BY allConns DESC

uwagi: Wersja SQL jest nie tylko dłuższa, ale i bardziej niewygodna, ponieważ należy zawsze brać pod uwagę kierunek strzałek w MATCH
.
Przypadek 2: Góra najdłuższe ścieżki
motywacja: długie łańcuchy zależności są podatne na kruchość. Na przykład zależność od biblioteki.
Neo4j ’ scypher:
// The WHERE is to filter out duplicate paths, e.g. A->B = B->A.
MATCH p=(n)--(m)
WHERE ID(n) < ID(m)
RETURN n.name, m.name, length(p) AS len, AS node_list
ORDER BY len DESC

Wykres SQL Server 2019:
WITH CTE(from_id, to_id, , )
AS
(
SELECT $from_id, $to_id, 1 AS , CONVERT(NVARCHAR(MAX), $to_id) AS
FROM Talks
UNION ALL
SELECT t.$from_id, t.$to_id, +1, CONVERT(NVARCHAR(MAX), CTE. + ',' + CONVERT(NVARCHAR(MAX), $to_id))
FROM Talks t JOIN CTE ON t.$to_id = CTE.
)
SELECT vap., ,
FROM CTE JOIN (SELECT MAX(c.) AS maxLevel FROM CTE c GROUP BY c.) myMax ON CTE. = myMax.maxLevel JOIN
view_AllPeople vap ON CTE. = vap.
ORDER BY DESC

uwagi: W wersji SQL Server, trzeba odwołać się do rekurencyjnej techniki Common table Expression. Zasadniczo obejmuje on sposób myślenia o relacyjnych bazach danych, aby rozwiązać problemy z Grafami.
wniosek
w domenie grafu polecenie SQL Server, z funkcją grafu wykorzystywaną lub nie, używane do rozwiązywania problemów z grafem, jest zwykle znacznie dłuższe, a także bardziej złożone w porównaniu z Cypherem Neo4j. Prowadzi to do wniosku, że kod będzie bardziej czasochłonny do opracowania i trudne do późniejszego utrzymania i rozszerzenia. Inny inżynier, a nawet oryginalny, patrząc na ten sam fragment kodu miesiąc później, zrozumie wszystkie jego aspekty. Dobrze znanym terminem opisującym tę sytuację jest dług techniczny.
łącząc wszystkie wyżej wymienione punkty, od aspektu kodu, przez obsługę funkcji, po ekosystem narzędzi/bibliotek, funkcjonalność Wykresów SQL Server, choć jest zachęcająca, nie spełnia oczekiwań.
SQL Server jest niezwykle dojrzały w odniesieniu do relacyjnej bazy danych, ale wyraźnie nowicjusz w Graph Database. Wsparcie dla tego grafu jest prawdopodobnie uważane za zawarte w relacyjnej bazie danych.