程序员社区

开发人员必备的数据库基础

关于使用数据库时常忽略的几个方面。

开发人员必备的数据库基础插图

在过去的几周里,作为我日常工作的一部分,我一直在深入研究数据库,将现有的Postgres 9x数据库迁移到更新版本的数据库,比如Postgres 13。作为一个SRE,我一般不太了解我所支撑的应用程序的数据库层,只是维护让它们可用并确保迁移脚本等成功运行。但是这次深入的研究让我有时间了解我们的数据库及其结构,并了解我们的应用程序的一些内部工作原理。今天我想谈谈数据库——特别是从软件开发人员的角度来看关系型数据库,也许能帮助一些新的和有经验的开发人员更好地理解他们的数据存储。

选择合适的工具

我想谈论的第一件事可能是其中最具争议的话题,那就是为您的应用程序选择正确的数据库。现在,我知道不是每个人都能够为他们的项目选择DB,但我认为了解一些最流行的DB及其优缺点将会有所帮助。

首先,有关DB类型的问题:关系型、非关系型(或NoSQL)和键值(或KV)。

我想指出的一件事是,直接将数据库分为SQL和NoSQL的二分法是有点用词不当,因为关系数据库不必使用SQL,而非关系数据库可以使用SQL。但是SQL和NoSQL已经成为关系和非关系的简写,所以我将在本文的其余部分使用这些术语。

关系数据库——有时缩写为RDBMS或SQL数据库——存储两种数据:结构化数据以及这些数据位之间的关系。这使得SQL数据库可以灵活地进行查询,并且更容易地只获取您想要的数据,因为与NoSQL数据库相比,数据更容易被分散到多个表(或规范化)中。规范化减少了数据冗余并提高了数据完整性,因为您每次只需要存储一行数据,只需在需要时引用它。SQL数据库的常见例子有PostgreSQL、MariaDB和Microsoft SQL Server。

NoSQL或非关系数据库有许多不同的风格(太多了,在此不便赘述),但最常见的可能是文档数据库。数据不像SQL DB那样存储在多个表中,而是作为文档存储在一起。文档是半结构化的,因为它们通常以某种编码(如JSON或XML)存储,但被编码的数据不需要遵循一致的格式。可以在单个文档数据库中存储不同类型(或模式)的文档。文档数据库具有SQL数据库所没有的灵活性,根据您所处理的数据,这可能是一个优势。流行的文档数据库有MongoDB、Elasticsearch和Couchbase。

键值数据库类似于NoSQL数据库,因为从技术上讲,文档数据库是KV数据库的子集。然而,便于描述,我们将保持KV数据库独立,因为从应用程序的角度来看,它们服务于不同的场景。键值数据库本质上是哈希表,因此在进行查找时可以非常快。这就是为什么它们通常被用作应用程序的缓存;他们的读取能力非常好。然而,KV数据库通常他们的数据类型是有限的,因此,处理复杂的数据可需要更多时间和处理过程。一些最流行的键值存储是Redis、Memcached和Consul。

现在我们有了基本数据库类型的概念,如何决定使用哪一种数据库?首先要看的是你需要存储的数据,然后确定五件事:

1、数据库需要存储什么类型的数据?

是否要存储日志文件?用户帐户?产品信息?JSON文档?数据类型将有助于正确选择SQL数据库还是NoSQL数据库。

2、将要存储的数据有多复杂?

数据可以很容易地被标准化吗?如果您的数据不能被标准化,那么NoSQL数据库可能是正确的选择。

3、数据是否一致?

所有的数据单元都遵循相同的模式?它能适应列类型吗?如果数据不是统一的,那么文档数据库可能是正确的选择。

4、数据是读频繁还是写频繁

这个应用程序是多读还是多写?一个写数据量大的应用程序可能需要一个在写数据量大的负载下执行良好的数据库。

5、 使用数据库时是否有环境或业务方面的考虑?

我们是否有任何合同或授权会影响我们对某个品牌或平台的决定?不需要遵守协议可能意味着使用像Microsoft SQL Server或Oracle数据库这样的东西,而不是像MariaDB这样的开源产品。

最后,选择哪个数据库不是能在一篇文章中讲得清楚的。这是开发团队在考虑了上述所有因素之后需要做出的决定。

数据库管理

下一个要问自己的问题是“我想如何管理我的数据库”?这似乎是一个愚蠢的问题,但是在编写SQL查询、使用SQL查询构造函数或使用成熟的ORM之间选择并不容易。ORM是什么?

ORM,或对象关系映射,是一种管理数据库中的对象并将数据库构造(表、列等)表示为所选编程语言中的对象的方法。通常,table用类表示,类属性表示为列,等等。使用ORM可以使工作变得非常简单,特别是在刚开始的时候,但是ORM也有其缺点。

orm必须是通用的。能够处理任何数据类型的各种查询,因此,它们倾向于对灵活性进行优化,而不是性能。使用ORM查询数据,特别是在大容量生产环境中,可能会导致延迟问题、死锁、锁定等,导致应用程序陷入停顿。我看到过一些orm处理一些非常古怪的事情,比如多个嵌套事务等等。但他们仍然有自己的用处。早期开发、原型设计和低容量数据库访问都是使用ORM。

或者,您可以简单地编写SQL查询语句。虽然这很可能为您提供最好的性能,但它也可能是一种更麻烦的查询数据的方式。而且,orm能自动转义特殊字符和引用字符串,如果您不太注意如何处理外部数据(特别是用户提供的数据),编写SQL可能会使您的应用程序受到SQL注入攻击。

介于两者之间的是SQL构造函数。它们提供了一些与orm相同的工具(减轻sql注入,一种更实用的查询方式),不会像orm会给表带来的一些开销。它们本质上是用于构造SQL语句的字符串构建器。为在orm和DIY SQL之间提供了一个中间选择。

索引

在理解数据库时,索引是最容易被忽视和也是最重要的方面之一。索引为数据库提供了一种快速查找表中的值的方法,而不必遍历表中的所有行。需要付出的代价是增加了存储索引所需的存储空间,以及在向表中插入新值时增加了写时间,因为数据库还需要更新索引查找。SQL数据库中的大多数表都有一个主键,该主键被数据库自动添加索引;此外,还可以在表中指定要建立索引的其他列。

假设您正在处理一个用户表,并且希望在用户输入用户名时检索他们的电子邮件。我们的表格看起来像这样:

id*| username      | email        
-------------------------------------------------
1  | user_ted      | ted@company.us
2  | user_jill     | jill@company.us
3  | user_annie    | annie@company.us

在本例中,id是我们的主键,因此自动具有与之相关联的索引。不过,用户不会提交行ID,他们会提交username。由于表中只有三行,索引对性能的作用不大,但是当表增长到100行时会发生什么呢?1000行?10000行?随着新行添加到表中,对用户email的每次查询将花费越来越长的时间。通过向username列添加索引,我们可以将查询时间减少到几乎恒定的时间(或O(1))。同样,这也会消耗一些磁盘空间和写性能,但是由于查找用户的次数要比添加用户的次数多,只要我们还正常,这种折衷是必要的。不正常的做法是添加我们不需要的索引,比如给email添加索引,因为我们从不通过电子邮件地址查找。通过添加email索引,我们所做的只是增加插入的时间和不必要地使用磁盘空间。

健康检查

当您的应用程序将长时间连接到数据库时,定期检查数据库是否仍然可用是很有必要的做法。根据数据库驱动程序、语言和其他因素的不同,有一些方法可以轻松实现这一点,比如检查打开的连接,但有时最简单的方法是只运行一个DB查询。然而,您运行的查询类型取决于您的目标。

目标1、需要确定所有的表都正常

Ok,我理解确保数据库处于可用状态的目标。然而,我不建议将此作为常规健康检查。我会在应用程序启动时执行这种验证步骤。首先,获取table列表将给数据库带来读取负载。它可能很小,但如果应用程序的多个副本同时运行,执行相同的健康检查,那么性能影响将更大。如果你坚决需要这么做的话,必须提前清楚这会带来性能影响。

目标2:想要得到数据库统计数据

我喜欢这个目标。从数据库中获取统计数据(如读/写负载)将非常有用,应用程序可以记录下来以便以后使用。除了数据库的可用性状态外,应用程序本身不能利用这些信息做很多事情,但它可能有助于以后进行故障排除。

目标3:我只是想确认DB是否启动

至少对我来说,这可能是最基本、最符合逻辑的健康检查。其他的事情,比如DB性能或验证等等,都可以单独处理,并由其他工具来处理。检查基本可用性是您的应用程序真正关心的惟一事情,因此在我看来,保持简单是最好的方法。那么应该使用什么样的查询呢?你绝对不想做的是这样的事:

SELECT * FROM 'Customers';

这种查询语句是必须停止的。 没错,这能检查数据库是否活着。但它会返回给你一个所有客户的列表,这个列表会随着你的客户群的增长而增长,这意味着你的健康检查在执行时间上也会增长。不要这样做。这是我最近看到的真实情况,确实发生过。相反,最好和最简单的查询是:

SELECT 1;

这本质上类似如下功能:

def my_function():
    return

简单,能达到效果。没有比这更好的了。

结束语

本文只是对与数据库相关工作内容的简要介绍,但是我希望它能对一些经常被忽视的领域提供一些见解。记住:数据库通常会成为应用程序的性能瓶颈,所以要善待它,并寻找方法使它们更快。

原文:https://betterprogramming.pub/db-101-databases-for-developers-f7dc29f46f2c

赞(0) 打赏
未经允许不得转载:IDEA激活码 » 开发人员必备的数据库基础

一个分享Java & Python知识的社区