【IT168评论】我们都有过这样的经历,从SQL数据库中提取数据,而需要提取数据的查询是一个复杂的查询,有多个表连接、过滤条件和复杂的WHERE语句。像MySQL和PostgreSQL这样的数据库,非常擅长执行复杂的连接、过滤和排序,以便从查询中准确获得所需的数据。
如果在数据库中执行这些操作,所做的实际上是将业务逻辑从应用程序里抽出,并将其移到数据库逻辑当中。最终你会使用更多的数据库资源和更少的应用服务器资源,来实现所期望的数据检索结果。
在实现数据插入要求时,也是如此。在执行数据插入之前,不必验证所插入的数据是否有效、无冲突且在应用程序中完全正确,而是让数据库执行验证,将冲突标准放入数据库模式需求中,并让数据库在插入的数据中抛出错误。
应用程序资源更容易扩展
在某些情况下,你需要数据库做这些类型的验证和检查。并不是说,不要让你的数据库做任何应用逻辑。而是,应该让数据库尽可能少地做应用业务逻辑,尽可能多地在应用程序代码本身中执行应用业务逻辑。
一般来说,扩展应用服务器资源比扩展数据库服务器资源要容易得多。
对于大多数网络应用程序而言,当流量增加时,通常可以轻松地增加应用服务器,来处理增加的负载。但是,除非数据库也能扩展到处理增加的负载,否则额外的应用服务器并没有什么帮助。
观察应用程序的可用资源。您应该将数据库看作是由稀缺的计算资源组成的,而应用程序代码层(包括服务)是由随时可用的计算资源组成的,这些计算资源可以很容易地扩展。
数据库资源是稀缺的,计算资源随时可用。
一旦你能理解这种思维方式,你就会意识到在应用程序层中,放置尽可能多的逻辑,将有助于更容易地扩展。而将业务逻辑放在数据库层会极大地限制该业务逻辑的可伸缩性。
让数据库处理复杂的过滤问题
不可能总是把所有的业务逻辑放在应用层。有时,你必须把某些查询放在数据库里。这样做的一个有效原因,可能是为了控制返回结果的数量。假设一个查询在一个非常大的数据库表上有一个复杂的过滤条件:
在大型数据集上,执行复杂的过滤查询后,预期的结果可能只有表中的几条记录。*将从这几行返回所有数据。但是,如果希望在应用层,而不是数据库中,执行复杂的过滤查询,则通常需要先从数据库中检索所有的数据。你最终可能会出现这样的结果:
这将把mytable中所有数据返回给应用层。然后,应用层将扔掉任何没有通过它在数据上执行的过滤条件的行。这样做的问题是,为了执行这个需求,mytable的全部内容都必须被转移到应用层。对于大型数据集来说,这是不可接受的。
在许多情况下,简单地重构一个查询或一系列查询,可以避免此类问题,并允许你在应用程序中执行更多的逻辑,而不会产生不必要的数据流量。做到这一点的一个方法是将数据过滤与数据检索分离开来。
过滤与检索分离
我们经常把过滤结果和检索结果的概念合并到单个查询中。特别是当我们查看有很多数据的大表时,编写一个查询,执行所有的过滤和规范,选择我们需要的行,然后让查询从选择的行中,返回需要的所有数据,这是非常方便的。
就其本身而言,这似乎没什么问题。但是,当查询涉及到复杂的连接或其他复杂的操作时,它就会给数据库带来不小的负荷,使数据库资源紧张。
解决这个问题的方法是执行一个初始查询,只简单地从所有行中返回过滤查询所需的字段,然后在应用程序中执行过滤逻辑。让我们假设field1和field2是上述<复杂的过滤查询>中实际涉及的字段。所以,让我们在初始查询中只获得这些数据:
然后,我们可以在你的应用程序代码中对field1和field2执行复杂过滤器查询逻辑。这将导致我的表格中符合复杂查询的行的ID列表。一旦你有了匹配的ID列表,你就可以执行后续的查询,从预过滤的行中获取实际数据:
这两个查询都是非常简单的查询,不需要在数据库中进行复杂的操作。选择返回数据的必要业务逻辑是在应用层执行的,但需要从数据库传输到应用的无关数据很少。通过将查询分割成独立的过滤和数据检索查询,你已经重构了你的请求,并允许复杂的、资源密集的业务逻辑在应用程序中执行,而不是数据库。
避免对返回的结果进行操作
将业务逻辑从数据库移到应用程序层的另一种简单方法是避免对数据库中返回的结果执行计算;而是在应用程序中执行它们。因此,不要做这样的事情。
你可以这样做:
然后,在应用程序中对返回的结果执行POWER(SQRT(field1)*SIN(field2),5)的等效计算。其结果是,执行计算所需的所有计算都利用了现成的应用程序资源,而不是稀缺的数据库资源。
将连接转移到应用层
复杂的连接是需要大量数据库资源。与其在数据库中连接数据,不如将尽可能多地连接逻辑转移到应用层中。以这种方式重构代码,可以显著减少数据库的负载,同时提高可伸缩性。
当然,不可能总是以这些方式重构查询。有时,只需要在数据库本身中执行一个复杂的查询。但是,通过尽可能多地删除这些复杂的查询,你可以减少对稀缺的数据库资源的依赖,增加对高可用的应用级资源的依赖。
因此,下次当你看到使用多个连接和复杂过滤逻辑的大型、长且复杂的查询时,不要为此感到困难。相反,考虑用更简单的查询(可能是多个查询)和在应用程序层中执行的业务逻辑替换它的方法。
随着应用程序的扩展,你会感受到改进的灵活性。