在SQL数据库中,数据存储在类似电子表格的表中,具有行和列。每行代表一个单一记录,每列表示记录内的字段。
SQL数据库存储在哪里?
SQL数据库存储在数据存储系统中的单独服务器上,通常存储在硬盘或固态硬盘上。
例子:
常见的SQL数据库有MySQL、PostgreSQL、Oracle Database和Microsoft SQL Server。它们广泛应用于需要复杂事务和高效查询的应用程序,特别是在传统企业应用中。
二、SQL表中的数据结构
1.表
表是SQL数据库的基本构建块,类似于电子表格。每个表包含关于特定主题的数据,例如客户、订单或产品。
2.列
每个表由列组成,可以将其视为表的“字段”或“属性”。例如,“Customers”表可能有**customer_id**、**name**、**age**和**email**等列。
3.数据类型
SQL表中的每个列都需要具有指定的数据类型。常见的数据类型包括**INTEGER**、**VARCHAR**(可变字符串)、**BOOLEAN**、**FLOAT**、**DATE**等。
4.行
表中的每一行代表一个单一的记录。在“Customers”表中,一行将表示一个客户的所有数据,具体值为每列的实际值(例如,客户ID为123,姓名为“John Doe”等)。
三、关系和键
1.关系
SQL数据库中的关系定义了表之间的关系。最常见的类型包括:
- 一对一: 表A中的每一行仅与表B中的一行关联。
- 一对多(或多对一): 一张表中的单行可能与另一张表中的多行相关。
- 多对多: 表A中的行可能与表B中的多行相关,反之亦然。
2.键
键帮助我们在表之间建立这些关系。最常用的两个键是:
- 主键: 用于唯一标识表中的每一行的列(或一组列)。
- 外键: 用于在另一张表中唯一标识一行的列(或一组列)。它在两张表之间创建了链接。
3.连接表格
SQL使用**JOIN**子句基于它们之间的相关列来合并来自两个或多个表的行。
常见的连接类型包括**INNER JOIN**、**LEFT JOIN**、**RIGHT JOIN**和**FULL OUTER JOIN**。
4.连接两个表的SQL查询示例
假设我们有两个表,**Orders**(包含列**order_id**、**customer_id**和**order_date**)和**Customers**(包含列**customer_id**、**name**和**address**),以下是如何连接它们的方法:
(1) INNER JOIN(返回在两个表中具有匹配值的记录)
SELECT Orders.id, Customers.name
FROM Orders
INNER JOIN Customers
ON Orders.customer_id = Customers.customer_id;
(2) LEFT JOIN(返回左表中的所有记录以及右表中的匹配记录)
SELECT Orders.id, Customers.name
FROM Orders
LEFT JOIN Customers
ON Orders.customer_id = Customers.customer_id;
在这些示例中,**INNER JOIN**仅获取具有相应客户信息的订单,而**LEFT JOIN**获取所有订单,包括那些没有相应客户信息的订单(缺失值用NULL填充)。所使用的具体连接类型取决于数据的确切性质和所需的结果。
四、SQL模式
模式定义了整个数据库在这些表中的组织方式。它包括表、它们之间的关系以及每个表的结构(列和数据类型)。
它充当将数据存储在数据库中的蓝图,并确保数据有一致的组织。
五、索引
我想讨论的最后一个主题是SQL索引。SQL数据库中的索引是数据库搜索引擎可以用于加速数据检索的特殊查找表。
假设我们的示例“Customers”表有数千条记录。我们经常需要基于其城市查询客户,这不是表的主键。在这种情况下,在**city**列上创建索引可以显著加速这些查询。
1.没有索引
如果city列上没有索引,查询在找到特定城市(例如“纽约”)的客户时将需要进行完整的表扫描。特别是对于大表,这是低效的。
SELECT name, email
FROM Customers
WHERE city = 'New York';
2.有索引
为了优化这个查询,我们在city列上创建一个索引。
CREATE INDEX idx_city
ON Customers (city);
现在,当执行相同的查询时,数据库使用索引idx_city快速找到“纽约”中的所有客户,而不必扫描整个表。
SELECT name, email
FROM Customers
WHERE city = 'New York';
在大数据集中,性能差异最为明显。对于小表,影响可能微不足道,甚至由于维护索引的开销可能是负面的。
3.使用索引的时机
- 提高查询性能: 使用索引的主要原因是加速查询性能,特别是对于大表。没有索引,数据库必须执行完整的表扫描,这对于大表来说是一个缓慢的操作。
- 唯一约束: 索引可以为列强制执行唯一性,当您想要确保某些列中没有两行具有相同值时使用。
- 排序和分组速度: 索引通过高效定位和返回数据来提高数据检索操作的速度。它们特别有利于涉及JOIN、ORDER BY和GROUP BY子句的查询。
4.索引的缺点
虽然索引对提高查询性能至关重要,但它们伴随着一些权衡:
- 增加存储: 每个创建的索引都会消耗额外的磁盘空间。所需空间的大小取决于表的大小以及索引中使用的列的数量和类型。
- 维护开销: 每当在表中插入、删除或更新数据时,都必须更新索引。这意味着在具有许多索引的表上,写操作(INSERT、UPDATE、DELETE)可能较慢。
- 优化的复杂性: 拥有太多的索引可能使查询优化器的工作更加困难,可能导致次优的查询计划。
六、SQL中使用的数据结构
SQL数据库通常使用多种数据结构来存储、索引和管理数据。以下是SQL数据库中最常见的数据结构。
索引与表数据分开存储,通常以便于快速搜索和检索的结构进行优化:
- 大多数索引存储为B-树或其变体(如B+树)。B-树是SQL数据库中用于索引的最常见数据结构。它们允许快速查找、插入和删除。B-树保持数据排序,允许在对数时间内进行搜索、顺序访问、插入和删除。B+树是B-树的变体,通常用于数据库和文件系统。它们将所有实际数据存储在叶节点中,而内部节点仅包含指向叶节点的键。这种结构使它们特别适用于范围查询和完整表扫描。
- 哈希索引: 哈希索引使用哈希表和哈希函数将键映射到索引中的特定位置。对于已知的精确匹配的点查询,它们非常有效。然而,它们对于范围查询效率较低,并且不按排序顺序存储数据。
- 堆(未排序结构): 在一些简单情况下,数据库可能在小表或临时工作空间中使用堆结构。这意味着数据未排序,可以插入到有空间的地方。对于插入来说很快,但对于查询可能效率低下。
- 树和二叉树: 对于一些专业用途,数据库可能使用其他类型的树,包括二叉树、AVL树或红黑树,每种树都提供了不同的性能特征,用于平衡、搜索、插入和删除数据。
- R树: R树是一种用于空间访问方法的数据结构,用于索引多维信息,例如地理坐标。它们通常用于地理信息系统(GIS)和处理空间数据的数据库。
- Trie: Trie(前缀树)偶尔用于特殊情况,如索引某些字符串数据类型。它们可以提供一种有效的方式来搜索具有公共前缀的键。