Articles

Graphique de Microsoft SQL Server – Une tentative qui a échoué (pour l’instant)

Posted by admin
 TRAN Ngoc Thach
TRAN Ngoc Thach

Suivre

29 juin 2020 * 9 min de lecture

Avertissement: L’opinion dans cet article est la mienne seule, basée sur mon exposition limitée au graphique de SQL Server. Je ne suis en aucun cas un expert sur SQL Server. Je pourrais être biaisé envers Neo4j.

Avec l’utilisation croissante de la base de données graphique et la domination de Neo4j sur ce marché de niche, ainsi que son gain de performance important dans l’interrogation de données hautement connectées, il est compréhensible que Microsoft ne veuille pas être laissé de côté de cette méga-tendance.

À partir de SQL Server 2017, SQL Server offrait des fonctionnalités Graphiques, avec l’introduction du mot clé MATCH. Dans la version 2019, entre autres, deux nouvelles fonctionnalités notables ont été ajoutées : les contraintes de périphérie et l’utilisation de tables dérivées dans les requêtes MATCH. Plonger dans cette technologie assez longtemps, j’ai l’impression qu’à partir de maintenant:

  • La prise en charge des graphiques dans SQL Server est encore loin d’être une base de données graphique à part entière, par exemple Neo4j.
  • L’ajout de fonctionnalités est lentement incrémental.
  • La fonction Graphique est intégrée à contrecœur dans l’état d’esprit de la base de données relationnelle.

Entrons dans les détails !

Avantages & Inconvénients

Le mot-clé MATCH n’est, à mon avis, qu’un sucre syntaxique. Plutôt que:

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

… les utilisateurs peuvent à peu près raccourcir la requête comme:

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

La requête raccourcie est sans aucun doute agréable aux yeux. Cependant, dans le monde .NET, Entity Framework peut être préféré pour les applications logicielles orientées données; par conséquent, il n’y a pas besoin de commandes SQL en texte brut. Les développeurs laissent simplement le framework générer des requêtes optimales pour eux alors qu’ils se concentrent sur des abstractions de haut niveau. Par cette logique, l’effet agréable de MATCH est soudainement hors de propos. Pire, pour le moment, il n’y a même pas de feuille de route pour prendre en charge ces capacités de graphique dans Entity Framework (Core).

Par rapport à Neo4j, en regardant à nouveau les requêtes ci-dessus, il est inévitable que les utilisateurs plient leur état d’esprit graphique dans le monde de la base de données relationnelle. Nous devons encore déclarer à l’avance quelles tables, dans la clause FROM, pour effectuer la correspondance (Devrait-il plutôt s’agir du graphique considéré comme un « tout traversable » et on n’a pas besoin de se soucier de l’organisation détaillée des données?). Lorsque la connaissance du sens de la flèche dans MATCH est un must, les utilisateurs en viennent à réaliser le mappage 1-1 entre la clause MATCH et la clause JOIN d’origine, dans le sens où il faut distinguer le Nœud Source et le Nœud Cible. En revanche, la syntaxe de chiffrement de Neo4j permet de ne pas tenir compte de cette distinction. Tout cela ne change pas nécessairement la donne; mais simplement une question de commodité et de joie de développement. (Plus tard, dans le 1er cas d’étude, nous verrons que nous devons faire un UNION ALL à cause de cela.)

L’une des clés de la haute performance de la base de données graphique native dans la traversée des données connectées est la contiguïté sans index. Malheureusement, il n’y a pas une telle chose avec la fonctionnalité Graphique dans SQL Server:

Nous ne maintenons pas de liste d’adjacence sur chaque nœud ; nous stockons plutôt des données de périphérie dans des tables. Comme il s’agit d’une base de données relationnelle, le stockage de données sous forme de tables était un choix plus naturel pour nous

Un autre problème gênant est le manque d’outils de visualisation adaptés au graphique, à la fois pour le schéma et les données. Comme solution de contournement, les utilisateurs peuvent toujours créer un diagramme de schéma dans SSMS, mais ces tables de nœuds et de bords finissent par être des tables individuelles et déconnectées, même au cas où elles auraient des contraintes de bord. Entre autres choses, la technologie graphique devrait également apporter des appels visuels, facilitant ainsi la construction de requêtes correctes. L’absence de tels outils est frustrante et nuisible à la productivité des développeurs.

Diagramme pour les tables graphiques

Alors, que faisons-nous pour obtenir le schéma graphique? Je suppose que nous ouvrons chaque table de bord pour voir manuellement les contraintes, puis les raisonner, à l’aide d’un morceau de papier, pour comprendre l’ensemble du schéma graphique.

Contraintes de bord du graphique

En ce qui concerne la visualisation des données, j’ai essayé Microsoft Power BI avec un addon de Graphe dirigé par la force. Cependant, cet outil n’est pas gratuit et il ne prend pas en charge les fonctionnalités graphiques de SQL Server prêtes à l’emploi, ce qui signifie qu’il voit les tables de nœuds et de bords comme des tables de base de données normales. En examinant de près les listes de colonnes, il existe des noms de colonnes étranges, par exemple graph_id_..., from_obj_id.... Ce sont des colonnes internes, générées automatiquement lors de la création de tables de nœuds / de bords, inaccessibles de l’extérieur. Une erreur est générée, comme ci-dessous, par la fonction Get Data de Power BI lors de l’accès à ces colonnes.

Power BI – « Obtenir des données » à partir des tables graphiques de SQL Server

Pour résoudre ce problème, il faut créer une vue de base de données contenant uniquement des colonnes pertinentes / accessibles, par exemple from_id et to_id dans la Table des bords, node_id dans la Table des nœuds. Ensuite, dans Power BI, extrayez les données via cette vue. J’espère que je ne me trompe pas, le graphique Dirigé par la force de Power BI semble nécessiter une seule table composée de colonnes Source, Target, Weight, Source Type, Target Type, Link Type. Notre schéma d’exemple est simpliste; la création de cette table unique est donc triviale. Et si le schéma contenait des tables de nœuds + 20 et une table de bords + 10, pourrions-nous nous retrouver avec une seule table pour visualiser l’ensemble du graphique avec Power BI?

# Mise à jour le 04.07.2020: À bien y réfléchir, cela est sûrement possible même si cela reste lourd. Il faut commencer par des tables de bords, dans chacune desquelles les $from_id et $to_id sont jointes aux Tables de nœuds pertinentes afin de se traduire en propriétés partagées de tous les nœuds, par exemple Name ou Id. Ensuite, faites UNION ALL pour que tous se combinent dans la table unique finale requise par Power BI.

L’interrogation des nœuds et des arêtes est l’une des possibilités de la technologie graphique. Ce qui peut faire ressortir une base de données de graphes, c’est le support intégré mais extensible des algorithmes de graphes, tels que PageRank et Louvain Community Detection (alias. Modularité de Louvain). Malheureusement encore une fois, aucune fonctionnalité d’analyse de ce type n’est disponible dans le graphique de SQL Server, comme indiqué:

Certaines bases de données de graphiques fournissent des fonctions analytiques de graphiques dédiées telles que « chemin le plus court » ou « page rank. »SQL Graph ne fournit aucune fonction de ce type dans cette version. Encore une fois, les boucles T-SQL et les tables temporaires peuvent être utilisées pour écrire une solution de contournement pour ces scénarios.

Dans Neo4j, ces algorithmes sont facilement disponibles au niveau de la production, grâce à la Graph Data Science Library. De plus, il est open source. En général, la documentation est utile, mais parfois insuffisante. Avec l’open-source, les développeurs peuvent télécharger et découvrir comment un algorithme spécifique est implémenté; ou même recompiler la bibliothèque, avec des informations de journalisation supplémentaires, pour mieux comprendre. L’implémentation de PageRank en SQL est possible, mais des algorithmes plus complexes tels que la modularité de Louvain peuvent être difficiles. Néanmoins, de nombreux ingénieurs logiciels préfèrent être plus gênés par la logique métier, au lieu de s’enliser avec des détails techniques de bas niveau.

Last but not least, à mon avis, l’expression de table commune est une sorte de tables dérivées. Depuis SQL Server 2019, cette technique est officiellement censée être utilisable avec Graph:

Expression de table commune (CTE) avec des tables de graphiques et une clause de CORRESPONDANCE

Mais si elle suit la création d’une VUE, elle est réalisable:

Création d’une vue avec des tables de graphiques et une clause de CORRESPONDANCE

Je pense que c’est un signe d’incohérence. La 2ème approche nécessite une vue créée en permanence car il n’est pas possible de créer une vue temporaire dans SQL Server. Normalement, les utilisateurs surmontent cela avec CTE, mais encore une fois CTE ne fonctionne pas avec Graph, comme indiqué ci-dessus.

Cas d’étude

Un exemple de scénario : Étudiants et enseignants.

Chiffrage de 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)

Graphique de 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'));

Cas 1: Toutes les connexions entrantes et sortantes des nœuds

Motivation: Compter ces connexions pour chaque nœud est un moyen de savoir lesquelles sont les plus importantes.

Neo4j’Scypher:

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

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

Remarques: La version SQL est non seulement plus longue, mais aussi plus gênante car la direction des flèches dans MATCH doit toujours être prise en compte.

Cas 2: Chemins les plus longs

Motivation: Les longues chaînes de dépendance sont sujettes à être fragiles. Par exemple, dépendance à la bibliothèque.

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

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

Remarques: Dans la version SQL Server, il faut recourir à la technique d’expression de table Commune récursive. Il embrasse à peu près l’état d’esprit de la base de données relationnelle pour résoudre les problèmes de graphiques.

Conclusion

Dans le domaine des graphes, la commande SQL d’un serveur SQL, avec fonction Graphique utilisée ou non, utilisée pour résoudre les problèmes de Graphes, est généralement beaucoup plus longue et plus complexe, par rapport au chiffrement de Neo4j. Cela implique que le code sera plus long à développer et difficile à maintenir et à étendre ultérieurement. Un autre ingénieur ou même l’original, en regardant le même extrait de code un mois plus tard, trouvera frustrant d’en saisir tous les aspects. Un terme bien connu pour décrire cette situation est la dette technique.

En combinant tous les points susmentionnés, de l’aspect code à la prise en charge des fonctionnalités, en passant par l’écosystème d’outils/ bibliothèques, la fonctionnalité graphique de SQL Server à l’heure actuelle, bien qu’encourageante, est en deçà des attentes.

SQL Server est extrêmement mature en ce qui concerne la base de données relationnelle, mais clairement un débutant dans la base de données graphique. Ce support de graphique est probablement considéré comme contenu dans la mentalité de base de données relationnelle.

Related Post

Leave A Comment