Articles

Microsoft SQL Server Grafico – Un tentativo che cadde a breve (per ora)

Posted by admin
TRAN Ngoc Thach
TRAN Ngoc Thach

Seguire

Jun 29, 2020 · 9 min leggere

Disclaimer: L’opinione in questo articolo è solo mio, in base alla mia limitata esposizione a SQL Server Grafico. Non sono in alcun modo un esperto di SQL Server. Potrei essere prevenuto verso Neo4j.

Con il crescente uso del database grafico e il predominio di Neo4j in questo mercato di nicchia, così come il suo significativo guadagno di prestazioni nell’interrogazione di dati altamente connessi, è comprensibile che Microsoft non voglia essere lasciato fuori da questa mega-tendenza.

A partire da SQL Server 2017, SQL Server ha offerto funzionalità Graph, con l’introduzione della parola chiave MATCH. Nella versione 2019, tra le altre, sono state aggiunte due nuove funzionalità degne di nota: i vincoli di bordo e l’uso di tabelle derivate nelle query MATCH. Immergendomi in questa tecnologia abbastanza a lungo, ho l’impressione che, fin d’ora:

  • Il supporto grafico in SQL Server è ancora lontano da un database grafico a tutti gli effetti, ad esempio Neo4j.
  • L’aggiunta di funzionalità è lentamente incrementale.
  • La funzione Graph è a malincuore inserita nella mentalità del database relazionale.

Entriamo nei dettagli!

Pro& Contro

La parola chiave MATCH è, a mio parere, semplicemente uno zucchero sintatico. Piuttosto che:

SELECT *
FROM NodeTable1 nt1 JOIN EdgeTable et ON nt1.$node_id = et.$from_id JOIN NodeTable2 nt2 ON nt2.$node_id = et.$to_id

… gli utenti possono praticamente abbreviare la query come:

SELECT *
FROM NodeTable1 nt1, EdgeTable et, NodeTable2 nt2
WHERE MATCH(nt1-(et)->nt2)

La query abbreviata è indubbiamente piacevole agli occhi. Tuttavia, nel mondo. NET, Entity Framework può essere preferito per le applicazioni software orientate ai dati; in conseguenza di ciò non è necessario disporre di comandi SQL in testo semplice. Gli sviluppatori lasciano che il framework generi query ottimali per loro mentre sono focalizzati su astrazioni di alto livello. Con questa logica, l’effetto piacevole di MATCH è improvvisamente irrilevante. Peggio ancora, al momento, non esiste nemmeno una tabella di marcia nel supportare queste funzionalità del grafico in Entity Framework (Core).

Confrontando con Neo4j, guardando di nuovo le query di cui sopra, è inevitabile che gli utenti pieghino la loro mentalità del grafico nel mondo del database relazionale. Dobbiamo ancora dichiarare in anticipo quali tabelle, nella clausola FROM, eseguire la corrispondenza (dovrebbe piuttosto essere il grafico considerato come un “tutto attraversabile” e non è necessario preoccuparsi dell’organizzazione dettagliata dei dati?). Quando si conosce la direzione della freccia in MATCH è un must, gli utenti arrivano a realizzare la mappatura 1-1 tra la clausola MATCH e la clausola originale JOIN, nel senso che si deve distinguere il nodo di origine e il Nodo di destinazione. Al contrario, la sintassi Cypher di Neo4j consente di ignorare questa distinzione. Tutti questi non sono necessariamente un punto di svolta; ma semplicemente una questione di convenienza e gioia di sviluppo. (Più tardi, nel caso di studio 1st, vedremo che dobbiamo fare un UNION ALL a causa di questo.)

Una chiave per alte prestazioni del database grafico nativo nell’attraversare i dati connessi è l’adiacenza senza indice. Sfortunatamente, non esiste una cosa del genere con la funzione Graph in SQL Server:

Non stiamo mantenendo un elenco di adiacenza su ogni nodo; invece stiamo memorizzando i dati edge nelle tabelle. Poiché si tratta di un database relazionale, la memorizzazione dei dati sotto forma di tabelle è stata una scelta più naturale per noi

Un altro problema fastidioso è la mancanza di strumenti di visualizzazione su misura per il grafico, sia per lo schema che per i dati. Come soluzione alternativa, gli utenti possono ancora creare un diagramma schema in SSMS, ma tali tabelle Nodi e bordi finiscono come tabelle singole e disconnesse anche nel caso in cui abbiano Vincoli di bordo. Tra le altre cose, la tecnologia Graph dovrebbe anche portare appelli visivi, facilitando gli utenti a costruire query corrette. La mancanza di tali strumenti è frustrante e dannosa per la produttività degli sviluppatori.

Diagramma per tabelle di grafici

Quindi cosa facciamo per ottenere lo schema del grafico? Immagino che apriamo ogni tabella di bordo per vedere manualmente i vincoli, e poi ragioniamo su di essi, con l’aiuto di un pezzo di carta, per capire l’intero schema del grafico.

Graph’s Edge Constraints

Per quanto riguarda la visualizzazione dei dati, ho provato Microsoft Power BI con addon Graph Force-Directed. Tuttavia, questo strumento non è gratuito e non supporta le funzionalità grafiche di SQL Server pronte all’uso, il che significa che vede le tabelle Nodi e Bordi come normali tabelle di database. Esaminando attentamente gli elenchi di colonne, ci sono nomi di colonne dall’aspetto strano, ad esempio graph_id_...,from_obj_id.... Si tratta di colonne interne, generate automaticamente durante la creazione di tabelle Node/Edge, inaccessibili dall’esterno. Un errore viene generato, come di seguito, dalla funzione Get Data di Power BI se si accede a tali colonne.

Power BI – “Ottieni dati” dalle tabelle dei grafici di SQL Server

Per risolvere questo problema, è necessario creare una vista database contenente solo colonne pertinenti / raggiungibili, ad esempio from_id e to_id nella tabella dei bordi, node_id nella tabella dei nodi. Quindi in Power BI, estrai i dati attraverso quella vista. Spero di non sbagliarmi, il grafico Force Directed di Power BI sembra richiedere una singola tabella composta da colonne Source, Target, Weight, Source Type, Target Type, Link Type. Il nostro schema di esempio è semplicistico; quindi creare questa singola tabella è banale. Cosa succede se lo schema contenesse + 20 Tabelle di nodi e + 10 Tabelle di bordi, potremmo finire con una singola tabella per visualizzare l’intero grafico con Power BI?

#Aggiornato il 04.07.2020: Ripensandoci, questo è sicuramente possibile anche se è ancora ingombrante. Si dovrebbe iniziare dalle tabelle dei bordi, in ognuna delle quali $from_id e $to_id sono uniti alle tabelle dei nodi rilevanti per tradurre in proprietà condivise di tutti i nodi, ad esempio Name o Id. Quindi fare UNION ALL per tutti da combinare nella singola tabella finale richiesta da Power BI.

L’interrogazione di nodi e bordi è una delle possibilità della tecnologia Graph. Ciò che può far risaltare un database grafico è il supporto integrato ma estensibile per gli algoritmi grafici, come PageRank e Louvain Community Detection (aka. Modularità di Louvain). Purtroppo ancora una volta, non tali funzionalità di analisi disponibili nel grafico di SQL Server, come detto:

Alcuni database grafico forniscono funzioni analitiche grafico dedicato come “percorso più breve” o ” page rank.”SQL Graph non fornisce tali funzioni in questa versione. Ancora una volta, i loop T-SQL e le tabelle temporanee possono essere utilizzati per scrivere una soluzione alternativa per questi scenari.

In Neo4j, questi algoritmi sono facilmente disponibili a livello di produzione, grazie alla libreria Graph Data Science. Inoltre, è open-source. Generalmente, la documentazione è utile, ma a volte non sufficiente. Con open-source, gli sviluppatori possono scaricare e immergersi in come un algoritmo specifico è implementato; o anche ricompilare la libreria, con informazioni di registrazione aggiuntive, per capire ulteriormente. L’implementazione del PageRank in SQL è possibile, ma un algoritmo più complesso come la modularità di Louvain può essere impegnativo. Tuttavia, molti ingegneri del software preferiscono essere più infastiditi dalla logica aziendale, invece di essere impantanati con dettagli tecnici di basso livello.

Ultimo ma non meno importante, a mio avviso, Common Table Expression è una sorta di tabelle derivate. Dal momento che SQL Server 2019, questa tecnica dovrebbe ufficialmente essere praticabile con Graph:

Common Table Expression (CTE) con tabelle grafiche e clausola di CORRISPONDENZA

Ma se segue la creazione della VISTA, è eseguibile:

Creazione di viste con tabelle di grafici e clausola di CORRISPONDENZA

Penso che questo sia un segno di incoerenza. Il secondo approccio richiede una vista creata in modo permanente in quanto non è possibile creare una vista temporanea in SQL Server. Normalmente, gli utenti superano questo con CTE, ma ancora una volta CTE non funziona con Graph, come mostrato sopra.

Casi di studio

Uno scenario di esempio: studenti e insegnanti.

Cypher di 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)

Grafico di 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'));

Caso 1: Tutte le connessioni in entrata e in uscita dei nodi

Motivazione: contare queste connessioni per ogni nodo è un modo per scoprire quali sono più importanti.

Neo4j’sCypher:

MATCH (n)--()
RETURN n.name, COUNT(r) AS allCons
ORDER BY allCons DESC

SQL Server 2019 Grafico:

--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

Commento: La versione SQL non è solo più lunga, ma anche più scomoda in quanto la direzione delle frecce in MATCH deve essere sempre presa in considerazione.

Caso 2: Percorsi più lunghi in alto

Motivazione: le lunghe catene di dipendenza sono soggette a essere fragili. Ad esempio, dipendenza dalla libreria.

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

SQL Server 2019 Grafico:

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

Commento: Nella versione di SQL Server, si deve ricorrere alla tecnica di espressione della tabella comune ricorsiva. Abbraccia praticamente la mentalità del database relazionale per risolvere i problemi del grafico.

Conclusione

Nel dominio Graph, il comando SQL di un server SQL, con funzionalità Graph utilizzata o meno, utilizzata per affrontare i problemi del grafico, è in genere molto più lungo e più complesso, rispetto al Cypher di Neo4j. Ciò comporta un’implicazione che il codice richiederà più tempo per lo sviluppo e sarà difficile da mantenere ed estendere in seguito. Un altro ingegnere o anche quello originale, guardando lo stesso frammento di codice un mese dopo, troverà frustrante cogliere tutti i suoi aspetti. Un termine ben noto per descrivere questa situazione è il debito tecnico.

Combinando tutti i punti di cui sopra, dall’aspetto del codice, al supporto delle funzionalità, all’ecosistema di strumenti/librerie, la funzionalità del grafico di SQL Server al momento, sebbene sia incoraggiante, non è all’altezza delle aspettative.

SQL Server è estremamente maturo rispetto al database relazionale, ma chiaramente un principiante nel database grafico. Questo supporto grafico è probabilmente considerato contenuto nella mentalità del database relazionale.

Related Post

Leave A Comment