为什么不使用SQL而不是GraphQL?


20

最近,我了解了GraphQL,它声称比RESTful更好。但是,我开始怀疑为什么不将SQL语句简单地放入HTTP GET请求中。

例如,在GraphQL中,我将编写

{
  Movie(id: "cixos5gtq0ogi0126tvekxo27") {
    id
    title
    actors {
      name
    }
  }
}

这并不比它的SQL比较简单

SELECT id, title FROM movies WHERE id = cixos5gtq0ogi0126tvekxo27;
SELECT actors.name FROM actors, actors_movies WHERE actors.id == movies.actor_id AND movie.id == cixos5gtq0ogi0126tvekxo27;

也许我们可以对查询进行URL编码并发送到服务器

GET endpoint?q=SELECT%20id%2C%20title%20FROM%20movies%20WHERE%20id%20%3D%20cixos5gtq0ogi0126tvekxo27%3B%0ASELECT%20actors.name%20FROM%20actors%2C%20actors_movies%20WHERE%20actors.id%20%3D%3D%20movies.actor_id%20AND%20movie.id%20%3D%3D%20cixos5gtq0ogi0126tvekxo27%3B HTTP/1.1

是的,查询URL可能太长,但是如果您不关心REST遵从性,则可以将其放入POST请求的正文中。(顺便说一句,我认为需要对REST进行HTTP RFC的修订才能有意义:限制查询字符串的长度从一开始就将实现与规范混合在一起)

从客户端直接发出SQL的优势还在于

  1. 解析GraphQL不需要服务器端代码/库,从而减少了开发时间。
  2. 解析GraphQL不需要服务器端开销,从而减少了运行时间。
  3. SQL语句比GraphQL灵活得多,因为(在大多数情况下)GraphQL无论如何都会简化为SQL。
  4. 每个人都知道SQL。

那么,GraphQL与SQL相比有什么优势?


41
小鲍比表。
菲利普·肯德尔

1
1.我仍然可以通过任意复杂的SQL查询为您提供服务。2.恶意行为者绝不可能获得有效密钥……
Philip Kendall

3
@PhilipKendall你是对的,但是使用GraphQL(或REST或其他)也不能解决这些问题,对吗?
nalzok

7
@nalzok:SQL是图灵完备的,这意味着不可能进行静态验证。
约尔格W¯¯米塔格

3
这很容易理解为什么这是一个糟糕的主意。自己实施。在某个时候,您将意识到自己将时间主要花费在一件事情上:安全。不久之后,您将感到有些沮丧,因为您正在实施有顶盖的TOAD。然后,您将认识到在整个系统上映射行有多么困难,并且您将尝试在两端(客户端和服务器)重新发明ORM轮子。在您放弃时,您的PM会要求您报告:用户的服务情况如何好了吗?“ ...
Laiv

Answers:


30

基本上是抽象。

SQL要求您的客户知道您的确切数据库结构,这不好。最重要的是,分析SQL以基于作为输入发送的值执行特殊操作是一件非常困难的事情。整个软件几乎只为此负责。你知道那是什么吗?如果您猜对了数据库,那是对的。

由于没有直接公开SQL,因此您不会将API的使用方限制为数据库的内部表示形式。您可以轻松地仅公开要公开的内容。

并且由于API的客户端仅依赖于抽象,因此您可以在API输入和实际数据库之间自由地拥有尽可能多的层(安全性,缓存,在单个请求上从多个数据库加载数据等)。

对于公共服务而言,直接公开数据库绝不是正确的方法。但是,如果您有一些内部系统,那么可以肯定,您的方法可能是有道理的,但是即使那样,通过将数据库凭据提供给应用程序B,也可以比直接尝试从应用程序B直接连接到应用程序A的数据库更容易。带有用于数据库SQL语言的自定义HTTP接口。


为什么在RDBMS上执行实际查询之前,为什么不能仅将URL(或SQL查询)与Redis中的键进行比较?

因为这并不容易。即使有人使用非常简单的查询,例如:

SELECT st.id, jt.name
FROM some_table st
INNER JOIN join_table jt ON jt.some_table_id = st.id
WHERE st.name = 'hello
world' AND st.type = 'STANDARD'

如何确保结果正确缓存?该查询包括换行符,但是有人也可以通过以下方式编写查询:

SELECT st.id, jt.name FROM some_table st INNER JOIN join_table jt ON jt.some_table_id = st.id WHERE st.name = 'hello
world' AND st.type = 'STANDARD'

而且仍然应该按照与上述相同的方式进行缓存。我专门提供了一个其中字符串搜索包含新行的地方,因此,仅查找行尾并将其替换为空格在这里行不通,正确解析请求将更加复杂。

即使您确实解决了该问题,另一个查询也可以切换条件的顺序,并且查询看起来像这样:

SELECT st.id, jt.name
FROM some_table st
INNER JOIN join_table jt ON jt.some_table_id = st.id
WHERE st.type = 'STANDARD' AND st.name = 'hello
world'

而另一个请求可能包含一个冗余WHERE参数,如下所示:

SELECT st.id, jt.name
FROM some_table st
INNER JOIN join_table jt ON jt.some_table_id = st.id
WHERE st.type = 'STANDARD' AND st.name = 'hello
world' AND st.stype = 'STANDARD'

所有这些查询仍然应该返回相同的结果,应该以相同的方式进行缓存。但是处理所有可能的选项几乎是不可能的。这就是为什么您不能简单地将URL与Redis中的键进行比较。


这是一个很好的答案,但是请查看更新。
nalzok

19

从理论上讲,您没有理由不能公开这样的SQL接口。

实际上,SQL太强大了,无法有效地限制在您要公开的安全范围内。

即使只允许读取访问,错误的查询仍然会占用资源。

其他语言(例如graphQL)被设计为公开的。他们只是给用户一个关于他们已经看到的内容的过滤器选项。

使用这些语言的好处是,它们已经经历了您想要阻止用户使用SQL进行的所有操作并将它们从表中删除的所有事情。


2
感谢您的回答,但是您能否解释GraphQL如何解决资源消耗问题?流氓GraphQL查询仍然可以说“告诉我有关每部电影及其演员的所有信息”,从而产生庞大的图表,并耗尽我的DBMS和网络。
nalzok

但是我可以编写一个递归SQL查询,该查询将锁定您的表并完全阻止其他用户运行任何查询
Ewan

4
问题不是限制访问表或删除,而是SQL的复杂程度。您将允许创建临时表吗?如何执行CLI?循环?交易?子选择?游标?您如何区分何时可以接受这些事物的使用以及何时出现“不良”现象
Ewan

2

正如其他人提到的那样,直接在api中公开SQL是非常糟糕的选择。尽管GraphQL是它的名称,但它不是SQL的抽象,而是任何数据存储甚至其他服务的抽象。

如果您正在寻找更接近SQL的抽象,则可能需要看一下odata(如果您碰巧在.NET后端中工作,尽管可能存在其他实现)。


0

如果要公开像GraphQL这样的SQL,则可能需要像GraphQL这样的东西,因为您将需要隐藏重要信息并选择要在API中显示的内容,以确保安全。

GraphQl和SQL是不同的东西,SQL是查询数据库的语言,而GraphQL仅用于管理来自API的数据,在API中,您将需要使自己的模式显示和查询来管理它,等等。

在任何API中,您都需要做这些事情以确保安全,但是,如果您想要进行免费数据访问的东西也许行得通,那么您就会知道软件世界中的许多替代方案

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.