使用SQL查询构建器有哪些优势?


17

使用查询生成器而不是使用原始SQL有什么好处吗?

例如

$q->select('*')
  ->from('posts')
  ->innerJoin('terms', 'post_id')
  ->where(...)

vs:

SELECT * FROM posts WHERE ...

我看到许多框架都使用这些抽象层,但是我无法理解其好处。


我认为应该针对视图而不是针对表编写查询。我倾向于认为使用查询生成器的人倾向于不编写视图或要求DBA为他们创建视图。这样一来,他们就无法利用RDBMS的全部功能。
图兰斯·科尔多瓦

1
@ user61852:除了可能提供一些免费的安全性和筛选功能外,针对视图的查询还提供了哪些针对表的查询无法提供的内容?
罗伯特·哈维

4
@RobertHarvey与编程接口而不是具体类相同。去耦和灵活性。只要“合同”(视图)保持与以往一样“模拟”相同的列,基础表的设计就可以实现。
图兰斯·科尔多瓦

@ user61852足够公平。
罗伯特·哈维

@RobertHarvey我把它变成了答案。
图兰斯·科尔多瓦

Answers:


20

通过框架很好地编写SQL的抽象就是抽象。

手工编写SQL本身并没有那么糟糕,但是您开始遇到转义和清理问题,这变得一团糟。抽象层可以在后台处理所有这些工作,从而使您的代码干净整洁,并且无需进行大量mysql_real_escape_string()调用等操作。

另外,这带来了考虑SQL不同方言的可能性。并非所有数据库的构建都相同,并且关键字或某些功能的语法可能会有所不同。使用抽象层可以动态地为变量生成正确的语法。

尽管抽象层会带来性能上的损失,但与您收到的代码的整洁性和健壮性相比,它通常可以忽略不计。


1
我不认为RDBMS之间的SQL方言有所不同。在PHP中,有一个PDO为您执行清理操作
Anna K.

12
SQL方言确实有所不同,这就是为什么它们被称为方言。对于PDO,抽象层只是向我们隐藏了这些混乱情况。

@GlennNelson Anna表示任何一种方言,使用不同的后端(PSQL / MySQL / SQLite ...)
Izkata 2012年

2
@AnnaK。方言可能不会改变,但有时功能会有所不同。例如,MySQL(带有MyISAM引擎)不支持外键限制,而PostGres则支持。方言本身必须要处理这样的事情(这需要完全了解数据结构,就像Django ORM一样),或者更有可能的是:用户必须对如何使用它有所了解,这可能使它看起来像像方言一样变化,视情况而定。
Izkata 2012年

1
+1,让一款精巧的工具为您完成转义和消毒工作。如果还可以进行验证,那就更好了。
丹·雷

11

查询构建器是我的宠儿,所以我写了自己的Framework(Apeel)来避免使用它们!

如果您使用PDO(我绝对会建议您这样做),那么将为您处理输入。

就像其他人所说的那样,尽管它们确实使在数据库之间切换变得更加容易,但是它们倾向于支持“最低公分母”功能,或者对于更高级的功能要么不支持,要么性能较差。

从1986年左右开始,我就一直在开发具有数据库的系统,并且在所有这些时间里,除了需要更好的性能时,我很少遇到公司实际更改他们使用的数据库。如果您要更改数据库以获得更好的性能,那么花时间手动优化查询以从新数据库中获得最大收益就变得更加有意义,而不是为了简单起见而选择查询构建器。

花费大量时间来掌握查询生成器的qwirks(然后在切换到更好的查询器时重新学习)将花费在学习如何优化SQL上的工作效率更高。

无论如何,这就是为什么不使用它的原因,尽管有些人喜欢它们。


4

从理论上讲?是。Glenn Nelson指出了他们如何经常为您提供帮助。(如果它是一个好的查询生成器)。

在实践中?并不总是符合理论并可能导致问题。假设您正在针对一些流行的DBMS使用查询生成器,并且一切都变了。然后,客户要求您打他们的DBMS,其中包含您选择的查询生成器无法处理的一些怪癖。(当我不得不使用旧版本的Pervasive时遇到了这个问题。)

但!您绝对应该做的是分离出数据访问层,并确保可以根据需要交换一个新的数据访问层。这样一来,您便可以使用具有所有功能的酷炫的查询生成器,但是如果您需要为有关的数据库插入使用该奇数伪SQL的新查询生成器。


2
像数据库怪癖那样的事情是否应该事先解决?我的意思是找出您的客户正在使用的数据库,并相应地选择适当的框架/库,这是编写一行代码之前应进行的处理。

3

我认为查询生成器的日常实用好处是代码重用和遵循DRY原理的能力。

使用查询生成器,您可以将重复的SQL部分放入方法中。然后使用这些方法来编写复杂的SQL。一个示例是例如可重用的JOIN子句:

function joinTaskWithClient($queryBuilder) {
    $queryBuilder->join('task', 'contract', 'task.contract_id = contract.id')
                 ->join('contract', 'client', 'contract.client_id = client.id');
}

因此用法是:

$queryBuilder->select('client.name')
             ->from('client')
             ->where('task.id=:task')->setParameter('task', 42);
joinTaskWithClient($queryBuilder);

您可能会注意到-与手动收集SQL字符串的情况相比,使用查询生成器可以按任何顺序添加SQL部分(例如,在WHERE后面的JOIN部分)。另外,您可以阅读有关构建器模式的信息, 以了解其目的和优势。

我同意转义和消毒,但是也可以不使用查询生成器来实现。关于数据库类型/方言抽象-这是相当理论上和可疑的好处,实际上很少使用。


对我来说,这也是一个主要好处。另一个是通过将方法抽象化,您可以为方法赋予更有意义的名称,甚至可以由此创建一个领域特定语言,从而使意图更加清晰。您还可以传递查询构建器,并让不同的组件为其添加特定的位。最后但并非最不重要的一点是,我发现它使我可以将模式封装在有意义的命名方法后面。...我发现一些查询生成器在其中添加列时会愚蠢地覆盖较早的列,这使上面的许多内容无用...
malte

2

我将根据我的自定义SQL构建器(方言)的自述文件提供答案

(纯文本如下,删除了特定于库的引用)

要求

  1. 支持多个数据库供应商(例如,MySQL,PostgreSQL,SQLite,MS SQL / SQL Server,Oracle,DB2,..)
  2. 轻松扩展到新的数据库(最好通过与实现无关的配置设置)
  3. 模块化和与实现无关的可转移性
  4. 灵活直观的API

特征

  1. 基于语法的模板
  2. 自定义软视图支持
  3. db抽象,模块化和可移植性
  4. 准备好的模板
  5. 数据转义

我认为上述功能和要求概述了使用SQL抽象生成器的原因

大多数SQL构建器都支持上述大多数功能(尽管据我所知,我不认为所有列出的功能都受支持)

用例示例:

  1. CMS平台能够与多个数据库供应商一起使用(无需更改基础代码)
  2. 数据库供应商易于更改和/或dB模式是动态的自定义应用程序代码(这意味着许多查询无法进行硬编码,但仍需要足够抽象以使代码对更改具有鲁棒性)
  3. 使用生产中使用的另一个DB进行原型制作(至少对于某些代码,需要重复的代码库)
  4. 应用程序代码未紧密耦合到特定的数据库提供者和/或实现(即使在同一数据库供应商中,例如,数据库供应商的不同版本),因此更加健壮,灵活且模块化
  5. 查询和数据转义的许多常见情况都是由框架本身处理的,通常这既最佳又更快

最后,我有一个用例的例子。我正在构建一个应用程序,其中基础数据库模式(wordpress)不适合需要完成的数据查询类型,另外还必须使用一些WP表(例如,帖子)(因此具有全新的表)所有应用程序数据都不是一种选择)。

在那种情况下,能够创建类似MVC的应用程序,在其中可以通过自定义/动态条件查询模型,这使得查询硬编码几乎是一场噩梦。想象一下,必须支持使用联接查询多达2-3个表,并过滤条件以查看将哪个表与哪些表联接,并且还要照顾所需的别名等等。

显然,这是一个查询抽象用例,而且,它甚至需要(或至少从中受益)具有定义自定义软视图 (联合表的集合,就好像它们是适合该模型的一个自定义表)的能力。 。然后,它变得更加容易,清洁,模块化和灵活。在另一方面,应用程序(代码)还使用查询抽象层作为(数据库模式)规范化工具。有人说,这是面向未来的

如果明天人们决定需要一些额外的选项或数据,则很容易将它们添加到模型中几行就可以了,并且可以正常工作。另外,如果明天人们决定不再使用wordpress(因为应用程序松散地耦合到wordpress作为插件),那么在几行中更改(只是定义)模型也相对容易代码以适应新的架构。

明白了吗?


1

通常,这些查询的某些参数确实是某些值而不是常量。现在,它们中的许多基本上已从用户表单帖子中派生。因此,SQL注入攻击有很多可能性。因此,固有的查询格式确实需要完全验证。

现在,这并不是说我们不信任开发人员,但是查询的形成可能很容易,但是在所有地方重复所有可能的验证检查可能只是意味着您有时可能会偶然错过或修改查询,但不修改查询但不要不会更新验证检查。一些新手甚至可能知道错过这一点的所有危险。因此,查询构建器的抽象是非常必要的。


0

我曾经以为查询生成器是GUI应用程序,可让您在后台生成SQL时选择表并以图形方式进行联接,但现在我知道您也将查询生成器称为API,这些API提供了不必创建纯SQL查询的方式,让您自己抽象出SQL风格的潜在差异。

使用这样的查询生成器是很好的,但是我倾向于认为严重依赖它们的人通常不会问DBA:“嘿,这是我经常使用的查询,请从中创建一个视图”。

不要误会我的意思。

我认为您应该针对视图而不是针对表编写查询。不是出于安全或过滤的考虑,这是有充分理由的,但是出于相同的原因,您应该针对接口而不是针对具体类进行编码:解耦。视图就像“合同”,在OOP中,界面就像“合同”一样。您可以更改基础表,但是只要您强制视图对程序员显示相同的“契约”,代码就不会中断。

同样,不要误会我的意思,您可以使用查询生成器查询视图,但是许多视图作为一个迁移过程而存在,这是必须编写查询并询问您的DBA的产物:“请创建这个,请” 。

我是否认为通过不编写查询无法检测到创建某些视图的需要是错误的吗?

令我担心的另一件事是,新手程序员不必掌握SQL,这是人类创造的最精美的技术之一。


一位说“此查询运行不佳,让我们一起努力并改进它”的DBA怎么样?起初它可能工作得很好,但是现在遇到了问题。如果仅需要索引,为什么还要为此烦恼开发人员?
JeffO

那是完全不同的情况,完全可以。
图兰斯·科尔多瓦

我就像每次查询从表或视图中提取一条记录都会在开发过程中遇到瓶颈时都涉及DBA。
JeffO '16
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.