常用的关系型数据库都有哪些

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了常用的关系型数据库都有哪些相关的知识,希望对你有一定的参考价值。

常见的关系型数据库管理系统产品有Oracle、SQL Server、Sybase、DB2、Access等。 1.Oracle
Oracle是1983年推出的世界上第一个开放式商品化关系型数据库管理系统。它采用标准的SQL结构化查询语言,支持多种数据类型,提供面向对象存储的数据支持,具有第四代语言开发工具,支持Unix、Windows NT、OS/2、Novell等多种平台。除此之外,它还具有很好的并行处理功能。Oracle产品主要由Oracle服务器产品、Oracle开发工具、Oracle应用软件组成,也有基于微机的数据库产品。主要满足对银行、金融、保险等企业、事业开发大型数据库的需求。
2.SQL Server
SQL即结构化查询语言(Structured Query Language,简称为SQL)。SQL Server最早出现在1988年,当时只能在OS/2操作系统上运行。2000年12月微软发布了SQL Server 2000,该软件可以运行于Windows NT/2000/XP等多种操作系统之上,是支持客户机/服务器结构的数据库管理系统,它可以帮助各种规模的企业管理数据。
随着用户群的不断增大,SQL Server在易用性、可靠性、可收缩性、支持数据仓库、系统集成等方面日趋完美。特别是SQL Server的数据库搜索引擎,可以在绝大多数的操作系统之上运行,并针对海量数据的查询进行了优化。目前SQL Server已经成为应用最广泛的数据库产品之一。
由于使用SQL Server不但要掌握SQL Server的操作,而且还要能熟练掌握Windows NT/2000 Server的运行机制,以及SQL语言,所以对非专业人员的学习和使用有一定的难度。
3.Sybase
1987年推出的大型关系型数据库管理系统Sybase,能运行于OS/2、Unix、Windows NT等多种平台,它支持标准的关系型数据库语言SQL,使用客户机/服务器模式,采用开放体系结构,能实现网络环境下各节点上服务器的数据库互访操作。技术先进、性能优良,是开发大中型数据库的工具。Sybase产品主要由服务器产品Sybase SQL Server、客户产品Sybase SQL Toolset和接口软件Sybase Client/Server Interface组成,还有著名的数据库应用开发工具PowerBuilder。
4.DB2
DB2是基于SQL的关系型数据库产品。20世纪80年代初期DB2的重点放在大型的主机平台上。到90年代初,DB2发展到中型机、小型机以及微机平台。DB2适用于各种硬件与软件平台。各种平台上的DB2有共同的应用程序接口,运行在一种平台上的程序可以很容易地移植到其他平台。DB2的用户主要分布在金融、商业、铁路、航空、医院、旅游等各个领域,以金融系统的应用最为突出。
5.Access
Access是在Windows操作系统下工作的关系型数据库管理系统。它采用了Windows程序设计理念,以Windows特有的技术设计查询、用户界面、报表等数据对象,内嵌了VBA(全称为Visual Basic Application)程序设计语言,具有集成的开发环境。Access提供图形化的查询工具和屏幕、报表生成器,用户建立复杂的报表、界面无需编程和了解SQL语言,它会自动生成SQL代码。
Access被集成到Office中,具有Office系列软件的一般特点,如菜单、工具栏等。与其他数据库管理系统软件相比,更加简单易学,一个普通的计算机用户,没有程序语言基础,仍然可以快速地掌握和使用它。最重要的一点是,Access的功能比较强大,足以应付一般的数据管理及处理需要,适用于中小型企业数据管理的需求。当然,在数据定义、数据安全可靠、数据有效控制等方面,它比前面几种数据库产品要逊色不少。
参考技术A Access,MSDE 2000,Embedded Firebird,SQLite等都是可以免费再分发(free redistributable)的数据库。
相比而言,MSDE 2000 显著缺点是需要安装,最大优点是和服务器端的 SQL Server 编程模型一致,开发便利。
Access的显著缺点是功能较少,不支持事务等常用功能,最大优点是简单、多数开发者都很熟悉,部署也很方便。
SQLite支持事务,也是一款单文件数据库,比较不足的是 .NET Data Provider 还不是很成熟。
Firebird则同时具有:单文件、部署简单不需安装(只需 XCOPY 两个文件)、支持事务、存储过程、触发器,.NET Data Provider比较稳定成熟等优点。

这个星球上的数据库实在不胜枚举,这里只列一些我接触过的常见的。

可以稍微夸张点说,有交互的应用,起码得用一下数据保存,即便是自定义结构的数据保存,还是最常见的INI、XML等,都可以算是“数据库”,真正点的,如DBase系列、FoxBase、FoxPro、MSAccess、InterBase、MS SQL Server、Oracle、DB2等,这些是商业化的数据库,前面几个只能算是数据库,后面几个是RMDBS(关系型数据库管理系统)。

对应商业化的,有开源的:SQLite、SimpleSQL、Berkely DB、Minosse、Firebird( 前身是是Borland公司的InterBase)、PostgreSQL、mysql等。

□SQLite:大家可以看我的SQLite系列随笔,C编写的,可以跨操作平台,支持大部分ANSI SQL 92,它是嵌入式的轻量级关系形数据库引擎,只需要一个DLL,体积为250k,数据库也只是一个文件,零配置,便可工作。既然开源,你甚至可以把它嵌入你的程序中。核心开发人员只有一个,最近加入了另外一个,也就是2个人而已,实在佩服,目前发展到3.1.0,相当高效稳定,有开源驱动在sourceforge.net上有其ADO.NET Data Provider for SQLite :https://sourceforge.net/projects/adodotnetsqlite/ 。

□SimpleSQL:相对SQLite要大几倍,但也是轻量级的,功能稍微强大一点,C++编写,有OLE、Java等版本。

□Berkely DB:C++编写的大型关系型数据库系统,还额外地支持XML(把XML当成数据库),号称2百万的安装量,MySQL也只不过号称5百万安装量而已,跨平台。

□Minosse:纯C#编写的大型关系型数据库系统,理想是超越MS SQL Server!最新版本:0.2.0,真难得,纯Java写的看得多了,纯C#的,不是移植别人的,还是第一个,佩服作者:包含C/S和嵌入式版本,并可跨越大部分平台,因为它不用Windows的东西,可以在Mono下编译。

□Firebird:这个东西太牛了,目前有1.5稳定版本已经拥有大量特性,完全支持ANSI SQL92、98等,一些超酷的特性让人疯狂(1.0特性、1.5特性,从这里开始研究),主要开发人员是一个俄罗斯人,目前开发队伍已经扩大到近100人,有3种模式,单机独立,典型C/S,超级服务器。2.0版本和3.0版本将在近期推出,看完其路线图(2.0、3.0)你就会疯掉。有.NET驱动,目前是1.7beta版。主要特性:
◆A.C.I.D;
◆MGA(任何版本的引擎都可以处理同一数据库记录);
◆PSQL(存储过程)超级强大,ms sql相对的太次,它啥都能在服务器端实现并推送到客户端成为强大的报表,存储过程;
◆触发器都可以在客户端获取监控追踪;
◆自动只读模式;
◆创新的事务保证绝对不会出错;
◆24*7运行中仍然可以随时备份数据库;
◆统一触发器:任何操作都可以让某表唯一的触发器来总控;
◆大部分语言都可以写plug-in,并直接在存储过程中调用函数;
◆c->c++,更加少的代码但更加快的速度;
◆3种运行模式,甚至可以嵌入式;
◆主流语言都可以调用它;
◆动态sql执行;
◆事务保存点;

□PostgreSQL:POSTGRES数据库的后开源版本,号称拥有任何其他数据库没有的大量新特性,似乎目标是要做超大型的OO关系型数据库系统,目前已经发展到8.0,有.NET驱动,中文官方网站有详细介绍。

□MySQL:这个,不用说了吧?号称全球最受欢迎的开源数据库,但让我奇怪的是,PostgreSQL都有简体中文的支持:包括内核、管理工具、QA等等,在最新版本MySQL中,我却没有发现... ,有.NET驱动,其中MySQL Connector/Net就是原来在sf.net上的ByteFX.Data项目,作者已经加入了MySQL团队,参看《感慨 20 之开源的前途/钱图?(1数据库)》。

======================================================

最近在学习 Firebird Embeded Database。作为一款单文件型小型数据库,Firebird 具有很多吸引人的特征,比如支持事务、支持存储过程、触发器等,而且 Embeded 版本的 Firebird 在 .NET 开发中只需要拷贝两个文件:一个 fbembed.dll (非托管但不需要注册的动态链接库)和一个 ADO.NET Data Provider 的 FirebirdSql.Data.Firebird.dll。这些特征都非常适合那些需要在客户端存储一些数据,但又不想安装数据库(比如MSDE)软件的情形。

据称,在国外,需要使用客户端数据库的情况中,有30%左右的开发者选择Access,有30%的开发者选择MSDE 2000,有30%的开发者选择Embedded Firebird,剩余10%选择其他小型数据库,如SQLite,MySQL 等。

上面所说的Access,MSDE 2000,Embedded Firebird,SQLite等都是可以免费再分发(free redistributable)的数据库。相比而言,MSDE 2000 显著缺点是需要安装,最大优点是和服务器端的 SQL Server 编程模型一致,开发便利。Access的显著缺点是功能较少,不支持事务等常用功能,最大优点是简单、多数开发者都很熟悉,部署也很方便。SQLite支持事务,也是一款单文件数据库,比较不足的是 .NET Data Provider 还不是很成熟。Firebird则同时具有:单文件、部署简单不需安装(只需 XCOPY 两个文件)、支持事务、存储过程、触发器,.NET Data Provider比较稳定成熟等优点。

Firebird 本身有SuperServer和Embedded版本之分,后者只能本机访问,不接受TCP连接。对于开发者而言,从Embedded数据库切换到SuperServer,只需更改数据库连接串中的ServerType值就行。

但是,在你正式决定使用?Firebird 之前,请你注意下面这个 known issue(已知问题): Firebird 数据库文件不能放置在含有中文等字符的路径中。Firebird 的文件名不可以用中文字符,所在路径的任何部分如果含有中文字符,都将无法访问到数据库。举个例子,中文Windows桌面所在的目录一般是“C:\Documents and Settings\用户名\桌面”,如果数据库文件放置在桌面上,就无法访问到。当然,Firebird 内部是可以存储中文字符的,因为它支持 GB2312 和 UNICODE 等字符集。

需要注意一点,连接串中的 Database 地址如果使用相对路径,请一定注意这个相对路径是相对于 fbembed.dll 所在目录的。
参考技术B Nosql的全称是Not Only Sql,这个概念很早就有人提出。Nosql指的是非关系型数据库,而我们常用的都是关系型数据库。就像我们常用的mysql,oralce、sqlserver等一样,这些数据库一般用来存储重要信息,应对普通的业务是没有问题的。但是,随着互联网的高速发展,传统的关系型数据库在应付超大规模,超大流量以及高并发的时候力不从心。而就在这个时候,Nosql应运而生。

上面说的是NOSQL 的定义.Nosql和关系型数据库的区别,这里我说明一比较重要的区别。

存储格式: 关系型数据库是表格式的,存储在表的行和列中。他们之间很容易关联协作存储,提取数据很方便。而Nosql数据库则与其相反,他是组合在一起。通常存储在数据集中,就像文档、键值对或者图结构。举个例子,例如在游戏里面玩家的背包数据,我们都知道一个游戏里面的道具是很多,而且不确定玩家什么时候获取什么道具,这个时候如果想在关系数据库里面存储数据,这个表怎么建立就是一个很大的问题,如果你把所有的道具ID 当做表头 ,那么后续每增加一个道具,就需要修改这张表。如果你的表结构是 :

用户ID|道具ID|道具数量|道具特殊属性
那么可以想象一下 这张表随着用户的增多会变的多么的庞大。所以这个时候我们就需要一个能直接像操作玩家对象一样的数据库,这里比较代表性的就是mongo ,通过这个我们就可以看出nosql 数据库更适合存储结构不确定的数据。

存储扩展:这可能是两者之间最大的区别,关系型数据库是纵向扩展,也就是说想要提高处理能力,要使用速度更快的计算机。因为数据存储在关系表中,操作的性能瓶颈可能涉及到多个表,需要通过提升计算机性能来克服。虽然有很大的扩展空间,但是最终会达到纵向扩展的上限。而Nosql数据库是横向扩展的,它的存储天然就是分布式的,可以通过给资源池添加更多的普通数据库服务器来分担负载。

上面的的例子已经说明了这个问题。在现代互联网时代大家都是希望能横线扩展服务。这样付出的代价是最小的。

对于上面关系型数据库和NOSQL 数据库的区别其实还有很多。我相信大家在用的都会感觉到。上面列出的只是我感觉区别最大的。

那么NOSQL 这么好用,是不是都可以用了呢,显示不是这样,NOSQL 对于聚合查询显示不是他的强项。这个时候就需要关系型数据库。我是这样建议,对于结构统一,应该存储于关系型数据库,对于结构不统一的可以存储到NOSQL数据库例如mongo 。但是这个不是绝对的,在实际的项目的开发过程中,需要根据的自己的业务,仔细揣摩一下,做好最合适的划分。

常见关系型数据库通常有SQL Server,Mysql,Oracle等。主流的Nosql数据库有Redis,Memcache,MongoDb。大多数的关系型数据库都是付费的并且价格昂贵,成本较大,而Nosql数据库通常都是开源的。在互联网行业用大多也是免费的MYSQL(这里偷笑一下)。

在实际的项目中大家的项目都是如何选择的呢?大家可以关注我,私信或者在评论区留言。
参考技术C 关系模型就是指二维表格模型,因而一个关系型数据库就是由二维表及其之间的联系组成的一个数据组织。当前主流的关系型数据库有Oracle、DB2、Microsoft SQL Server、Microsoft Access、MySQL等。 参考技术D

1、存储引擎:MySQL中的数据用各种不同的技术存储在文件(或者内存)中。这些技术中的每一种技术都使用不同的存储机制、索引技巧、锁定水平并且最终提供广泛的不同的功能和能力。通过选择不同的技术,你能够获得额外的速度或者功能,从而改善你的应用的整体功能。

2、索引设计:索引和表一般要创建在不同的表空间中,以提高IO性能。因为索引不会在空值上生效,所以如果某列有空值且希望建立索引,那么可以考虑建立组合索引(colName, 1)。

3、sql优化器(商业数据库竞争的核心):由于移动设备的资源限制,嵌入式移动数据库一般和应用系统集成在一起,作为整个应用系统的前端而存在,而它所管理的数据集可能是后端服务器中数据集的子集或子集的副本。

4、事务管理与并发控制:在事务处理中,一旦某个操作发生异常,则整个事务都会重新开始,数据库也会返回到事务开始之前的状态,在事务中对数据库所做的一切操作都会取消。事务要是成功的话,事务中所有的操作都会执行。

5、容灾与恢复技术:基于数据同步复制技术,通过实时同步I/O,实现服务器和数据库数据从源端到目标端的持续捕获(RPO趋近于0,注:RPO=最后备份与发生灾难之间的时间,也是业务系统所允许的在灾难过程中的最大数据丢失),并且可以全自或手动创建数据恢复点,以确保数据发生错误时,恢复数据到最新的时间点。

在关系数据库中存储分层数据的选项都有哪些?

【中文标题】在关系数据库中存储分层数据的选项都有哪些?【英文标题】:What are the options for storing hierarchical data in a relational database?在关系数据库中存储分层数据的选项有哪些? 【发布时间】:2011-05-02 04:19:38 【问题描述】:

良好的概述

一般来说,您是在快速读取时间(例如,嵌套集)或快速写入时间(邻接列表)之间做出决定。通常,您最终会得到最适合您需求的以下选项的组合。以下提供了一些深入阅读:

One more Nested Intervals vs. Adjacency List comparison:我发现的邻接列表、物化路径、嵌套集和嵌套区间的最佳比较。 Models for hierarchical data:幻灯片很好地解释了权衡和示例用法 Representing hierarchies in MySQL: 对嵌套集的概述非常好,尤其是 Hierarchical data in RDBMSs:我见过的最全面和组织良好的一组链接,但解释的方式并不多

选项

我知道的和一般特征:

    Adjacency List:
列:ID、ParentID 易于实施。 廉价的节点移动、插入和删除。 昂贵的寻找关卡、祖先和后代、路径 在支持它们的数据库中避免通过Common Table Expressions 进行 N+1
    Nested Set(又名Modified Preorder Tree Traversal)
列:左、右 廉价的祖先,后代 由于易失编码,O(n/2) 移动、插入、删除非常昂贵
    Bridge Table(又名Closure Table /w triggers)
使用带有祖先、后代、深度的单独连接表(可选) 廉价的祖先和后代 插入、更新、删除的写入成本 O(log n)(子树的大小) 规范化编码:适用于连接中的 RDBMS 统计信息和查询规划器 每个节点需要多行
    Lineage Column(又名Materialized Path,路径枚举)
列:血统(例如 /parent/child/grandchild/etc...) 通过前缀查询便宜的后代(例如LEFT(lineage, #) = '/enumerated/path') 插入、更新、删除的写入成本 O(log n)(子树的大小) 非关系型:依赖数组数据类型或序列化字符串格式
    Nested Intervals
类似于嵌套集,但使用实数/浮点数/十进制数,因此编码不是易失性的(廉价的移动/插入/删除) 存在实数/浮点数/十进制表示/精度问题 Matrix encoding variant 为“免费”添加了祖先编码(物化路径),但增加了线性代数的技巧。
    Flat Table
修改后的邻接列表,为每条记录添加一个级别和排名(例如排序)列。 迭代/分页成本低 昂贵的移动和删除 良好用途:线程讨论 - 论坛/博客 cmets
    Multiple lineage columns
列:每个血统级别一个,指的是所有父级,直到根,从项目级别向下的级别设置为 NULL 便宜的祖先,后代,等级 便宜的插入、删除、移动叶子 内部节点的昂贵插入、删除、移动 层次结构深度的硬性限制

数据库特定说明

MySQL

Use session variables for Adjacency List

甲骨文

使用CONNECT BY遍历邻接表

PostgreSQL

ltree datatype 用于物化路径

SQL 服务器

General summary 2008 提供了 HierarchyId 数据类型,似乎有助于使用沿袭列方法并扩展可表示的深度。

【问题讨论】:

根据slideshare.net/billkarwin/sql-antipatterns-strike-back 第77 页,Closure Tables 在易用性方面优于Adjacency ListPath EnumerationNested Sets(我也在猜测性能)。 我在这里错过了一个非常简单的版本:一个简单的 BLOB。如果您的层次结构只有几十个项目,则序列化的 id 树可能是最佳选择。 @Lothar:问题是一个社区 wiki,所以请随意使用。我在这方面的想法是,我只会使用那些支持某种 blob 结构的数据库,例如 XML 和稳定的查询语言,例如 XPATH。否则,除了在代码中而不是 SQL 中检索、反序列化和 munge 之外,我看不到查询的好方法。如果您确实遇到需要大量任意元素的问题,您可能最好使用像 Neo4J 这样的 Node 数据库,我已经使用并喜欢它,尽管它从未用于生产。 对于 MS SQL Server:Combination of Id-ParentId and HierarchyId Approaches to Hierarchical Data “General Summary”的 MSDN 链接不再显示该文章。它出现在 2008 年 9 月版的 MSDN 杂志中,您可以将其下载为 CHM 文件,或通过 Web 存档查看:web.archive.org/web/20080913041559/http://msdn.microsoft.com:80/… 【参考方案1】:

这是对您问题的部分回答,但我希望仍然有用。

Microsoft SQL Server 2008 实现了两个对管理分层数据非常有用的功能:

HierarchyId 数据类型。 常用表表达式,使用with关键字。

请查看 MSDN 上 Kent Tegels 的 "Model Your Data Hierarchies With SQL Server 2008" 以了解开始。另请参阅我自己的问题:Recursive same-table query in SQL Server 2008

【讨论】:

有趣,HierarchyId,不知道那个:msdn.microsoft.com/en-us/library/bb677290.aspx 确实如此。我处理大量递归分层数据,我发现公用表表达式非常有用。有关介绍,请参阅 msdn.microsoft.com/en-us/library/ms186243.aspx。【参考方案2】:

我最喜欢的答案是该线程中的第一句话所建议的。使用邻接表维护层次结构,使用嵌套集查询层次结构。

到目前为止的问题是从邻接列表到嵌套集的覆盖方法非常缓慢,因为大多数人使用称为“推栈”的极端 RBAR 方法进行转换,并且被认为是通过邻接表维护的简单性和嵌套集的出色性能达到涅槃的方法是昂贵的。结果,大多数人最终不得不满足于一个或另一个,特别是如果有超过,比如说,糟糕的 100,000 个左右的节点。使用推送堆栈方法可能需要一整天的时间来转换传销者认为的百万级节点层次结构。

我想通过想出一种方法以似乎不可能的速度将邻接列表转换为嵌套集,我想给 Celko 带来一些竞争。这是我的 i5 笔记本电脑上推送堆栈方法的性能。

Duration for     1,000 Nodes = 00:00:00:870 
Duration for    10,000 Nodes = 00:01:01:783 (70 times slower instead of just 10)
Duration for   100,000 Nodes = 00:49:59:730 (3,446 times slower instead of just 100) 
Duration for 1,000,000 Nodes = 'Didn't even try this'

这是新方法的持续时间(括号中是推送堆栈方法)。

Duration for     1,000 Nodes = 00:00:00:053 (compared to 00:00:00:870)
Duration for    10,000 Nodes = 00:00:00:323 (compared to 00:01:01:783)
Duration for   100,000 Nodes = 00:00:03:867 (compared to 00:49:59:730)
Duration for 1,000,000 Nodes = 00:00:54:283 (compared to something like 2 days!!!)

是的,没错。 100 万个节点在不到 1 分钟的时间内完成转换,100,000 个节点在 4 秒内完成。

您可以在以下 URL 阅读有关新方法的信息并获取代码副本。 http://www.sqlservercentral.com/articles/Hierarchy/94040/

我还使用类似的方法开发了“预聚合”层次结构。传销员和制作物料清单的人会对本文特别感兴趣。 http://www.sqlservercentral.com/articles/T-SQL/94570/

如果您确实停下来看看任何一篇文章,请跳转到“加入讨论”链接,让我知道您的想法。

【讨论】:

什么是传销商? MLM = "多层次营销"。安利、嘉康利、ACN等。【参考方案3】:

如果您的数据库支持数组,您还可以将沿袭列或物化路径实现为父 ID 数组。

特别是使用 Postgres,您可以使用集合运算符来查询层次结构,并通过 GIN 索引获得出色的性能。这使得在单个查询中查找父母、孩子和深度变得非常简单。更新也很容易管理。

如果你好奇的话,我有一篇关于使用 arrays for materialized paths 的完整文章。

【讨论】:

【参考方案4】:

尚未提及此设计:

Multiple lineage columns

虽然它有局限性,但如果你能承受它们,它是非常简单和非常高效的。特点:

列:每个血统级别一个,指的是直到根的所有父项,当前项级别以下的级别设置为0(或NULL) 层次结构的深度有一个固定限制 便宜的祖先,后代,等级 便宜的插入、删除、移动叶子 内部节点的昂贵插入、删除、移动

下面是一个示例 - 鸟类的分类树,因此层次结构是类/顺序/科/属/物种 - 物种是最低级别,1 行 = 1 个分类单元(在叶节点的情况下对应于物种) :

CREATE TABLE `taxons` (
  `TaxonId` smallint(6) NOT NULL default '0',
  `ClassId` smallint(6) default NULL,
  `OrderId` smallint(6) default NULL,
  `FamilyId` smallint(6) default NULL,
  `GenusId` smallint(6) default NULL,
  `Name` varchar(150) NOT NULL default ''
);

以及数据示例:

+---------+---------+---------+----------+---------+-------------------------------+
| TaxonId | ClassId | OrderId | FamilyId | GenusId | Name                          |
+---------+---------+---------+----------+---------+-------------------------------+
|     254 |       0 |       0 |        0 |       0 | Aves                          |
|     255 |     254 |       0 |        0 |       0 | Gaviiformes                   |
|     256 |     254 |     255 |        0 |       0 | Gaviidae                      |
|     257 |     254 |     255 |      256 |       0 | Gavia                         |
|     258 |     254 |     255 |      256 |     257 | Gavia stellata                |
|     259 |     254 |     255 |      256 |     257 | Gavia arctica                 |
|     260 |     254 |     255 |      256 |     257 | Gavia immer                   |
|     261 |     254 |     255 |      256 |     257 | Gavia adamsii                 |
|     262 |     254 |       0 |        0 |       0 | Podicipediformes              |
|     263 |     254 |     262 |        0 |       0 | Podicipedidae                 |
|     264 |     254 |     262 |      263 |       0 | Tachybaptus                   |

这很棒,因为这样您就可以非常轻松地完成所有需要的操作,只要内部类别不改变它们在树中的级别。

【讨论】:

【参考方案5】:

这真是一道方钉圆孔题。

如果关系数据库和 SQL 是您拥有或愿意使用的唯一锤子,那么到目前为止发布的答案就足够了。但是,为什么不使用旨在处理分层数据的工具呢? Graph database 是复杂分层数据的理想选择。

关系模型的低效率以及将图形/层次模型映射到关系模型的任何代码/查询解决方案的复杂性与图形数据库解决方案解决同样的问题。

将物料清单视为一种常见的分层数据结构。

class Component extends Vertex 
    long assetId;
    long partNumber;
    long material;
    long amount;
;

class PartOf extends Edge 
;

class AdjacentTo extends Edge 
;

两个子组件之间的最短路径:简单的图遍历算法。可接受的路径可以根据标准进行限定。

相似度:两个程序集之间的相似度是多少?对两个子树执行遍历,计算两个子树的交集和并集。相似百分比是交集除以并集。

传递闭包:遍历子树并总结感兴趣的字段,例如“一个子组件中有多少铝?”

是的,您可以使用 SQL 和关系数据库来解决问题。但是,如果您愿意为工作使用正确的工具,还有更好的方法。

【讨论】:

如果用例演示或更好地对比了如何使用 SPARQL 而不是 RDBMS 中的 SQL 来查询图形数据库,则此答案将非常有用。 SPARQL 与 RDF 数据库相关,RDF 数据库是更大的图形数据库领域的子类。我使用 InfiniteGraph,它不是 RDF 数据库,目前不支持 SPARQL。 InfiniteGraph 支持几种不同的查询机制:(1) 用于设置视图、过滤器、路径限定符和结果处理程序的图形导航 API,(2) 复杂的图形路径模式匹配语言,以及 (3) Gremlin。【参考方案6】:

邻接模型+嵌套集模型

我选择它是因为我可以轻松地向树中插入新项目(您只需要一个分支的 id 就可以向其中插入一个新项目)并且查询速度也很快。

+-------------+----------------------+--------+-----+-----+
| category_id | name                 | parent | lft | rgt |
+-------------+----------------------+--------+-----+-----+
|           1 | ELECTRONICS          |   NULL |   1 |  20 |
|           2 | TELEVISIONS          |      1 |   2 |   9 |
|           3 | TUBE                 |      2 |   3 |   4 |
|           4 | LCD                  |      2 |   5 |   6 |
|           5 | PLASMA               |      2 |   7 |   8 |
|           6 | PORTABLE ELECTRONICS |      1 |  10 |  19 |
|           7 | MP3 PLAYERS          |      6 |  11 |  14 |
|           8 | FLASH                |      7 |  12 |  13 |
|           9 | CD PLAYERS           |      6 |  15 |  16 |
|          10 | 2 WAY RADIOS         |      6 |  17 |  18 |
+-------------+----------------------+--------+-----+-----+
每次您需要任何父母的所有孩子时,您只需查询parent 列。 如果您需要任何父级的所有后代,您可以查询其lft 介于父级的lftrgt 之间的项目。 如果您需要任何节点的所有父节点直到树的根,您查询具有低于节点lftrgt 大于节点rgt 的项目并按@ 排序987654331@.

我需要让访问和查询树比插入更快,这就是我选择这个的原因

唯一的问题是在插入新项目时修复leftright 列。好吧,我为它创建了一个存储过程,并在每次插入一个新项目时调用它,这在我的情况下很少见,但它真的很快。 我从 Joe Celko 的书中得到了这个想法,DBA SE 中解释了存储过程以及我是如何想到它的 https://dba.stackexchange.com/q/89051/41481

【讨论】:

+1 这是一种合法的方法。根据我自己的经验,关键是决定在发生大型更新操作时是否可以接受脏读。如果没有,这将成为问题或阻止人们直接查询表并始终通过 API - 数据库存储过程/函数或代码。 这是一个有趣的解决方案;但是,我不确定在尝试查找子列时查询父列是否真的提供了任何主要优势——这就是为什么我们首先有左列和右列。 @Thomas,childrendescendants 之间存在差异。 leftright 用于查找后代。【参考方案7】:

我将 PostgreSQL 与我的层次结构的闭包表一起使用。 我有一个用于整个数据库的通用存储过程:

CREATE FUNCTION nomen_tree() RETURNS trigger
    LANGUAGE plpgsql
    AS $_$
DECLARE
  old_parent INTEGER;
  new_parent INTEGER;
  id_nom INTEGER;
  txt_name TEXT;
BEGIN
-- TG_ARGV[0] = name of table with entities with PARENT-CHILD relationships (TBL_ORIG)
-- TG_ARGV[1] = name of helper table with ANCESTOR, CHILD, DEPTH information (TBL_TREE)
-- TG_ARGV[2] = name of the field in TBL_ORIG which is used for the PARENT-CHILD relationship (FLD_PARENT)
    IF TG_OP = 'INSERT' THEN
    EXECUTE 'INSERT INTO ' || TG_ARGV[1] || ' (child_id,ancestor_id,depth) 
        SELECT $1.id,$1.id,0 UNION ALL
      SELECT $1.id,ancestor_id,depth+1 FROM ' || TG_ARGV[1] || ' WHERE child_id=$1.' || TG_ARGV[2] USING NEW;
    ELSE                                                           
    -- EXECUTE does not support conditional statements inside
    EXECUTE 'SELECT $1.' || TG_ARGV[2] || ',$2.' || TG_ARGV[2] INTO old_parent,new_parent USING OLD,NEW;
    IF COALESCE(old_parent,0) <> COALESCE(new_parent,0) THEN
      EXECUTE '
      -- prevent cycles in the tree
      UPDATE ' || TG_ARGV[0] || ' SET ' || TG_ARGV[2] || ' = $1.' || TG_ARGV[2]
        || ' WHERE id=$2.' || TG_ARGV[2] || ' AND EXISTS(SELECT 1 FROM '
        || TG_ARGV[1] || ' WHERE child_id=$2.' || TG_ARGV[2] || ' AND ancestor_id=$2.id);
      -- first remove edges between all old parents of node and its descendants
      DELETE FROM ' || TG_ARGV[1] || ' WHERE child_id IN
        (SELECT child_id FROM ' || TG_ARGV[1] || ' WHERE ancestor_id = $1.id)
        AND ancestor_id IN
        (SELECT ancestor_id FROM ' || TG_ARGV[1] || ' WHERE child_id = $1.id AND ancestor_id <> $1.id);
      -- then add edges for all new parents ...
      INSERT INTO ' || TG_ARGV[1] || ' (child_id,ancestor_id,depth) 
        SELECT child_id,ancestor_id,d_c+d_a FROM
        (SELECT child_id,depth AS d_c FROM ' || TG_ARGV[1] || ' WHERE ancestor_id=$2.id) AS child
        CROSS JOIN
        (SELECT ancestor_id,depth+1 AS d_a FROM ' || TG_ARGV[1] || ' WHERE child_id=$2.' 
        || TG_ARGV[2] || ') AS parent;' USING OLD, NEW;
    END IF;
  END IF;
  RETURN NULL;
END;
$_$;

然后为每个我有层次结构的表创建一个触发器

CREATE TRIGGER nomenclature_tree_tr AFTER INSERT OR UPDATE ON nomenclature FOR EACH ROW EXECUTE PROCEDURE nomen_tree('my_db.nomenclature', 'my_db.nom_helper', 'parent_id');

为了从现有层次结构中填充闭包表,我使用了这个存储过程:

CREATE FUNCTION rebuild_tree(tbl_base text, tbl_closure text, fld_parent text) RETURNS void
    LANGUAGE plpgsql
    AS $$
BEGIN
    EXECUTE 'TRUNCATE ' || tbl_closure || ';
    INSERT INTO ' || tbl_closure || ' (child_id,ancestor_id,depth) 
        WITH RECURSIVE tree AS
      (
        SELECT id AS child_id,id AS ancestor_id,0 AS depth FROM ' || tbl_base || '
        UNION ALL 
        SELECT t.id,ancestor_id,depth+1 FROM ' || tbl_base || ' AS t
        JOIN tree ON child_id = ' || fld_parent || '
      )
      SELECT * FROM tree;';
END;
$$;

闭包表定义为 3 列 - ANCESTOR_ID、DESCENDANT_ID、DEPTH。可以(我什至建议)存储 ANCESTOR 和 DESCENDANT 具有相同值的记录,而 DEPTH 的值为零。这将简化检索层次结构的查询。它们确实非常简单:

-- get all descendants
SELECT tbl_orig.*,depth FROM tbl_closure LEFT JOIN tbl_orig ON descendant_id = tbl_orig.id WHERE ancestor_id = XXX AND depth <> 0;
-- get only direct descendants
SELECT tbl_orig.* FROM tbl_closure LEFT JOIN tbl_orig ON descendant_id = tbl_orig.id WHERE ancestor_id = XXX AND depth = 1;
-- get all ancestors
SELECT tbl_orig.* FROM tbl_closure LEFT JOIN tbl_orig ON ancestor_id = tbl_orig.id WHERE descendant_id = XXX AND depth <> 0;
-- find the deepest level of children
SELECT MAX(depth) FROM tbl_closure WHERE ancestor_id = XXX;

【讨论】:

以上是关于常用的关系型数据库都有哪些的主要内容,如果未能解决你的问题,请参考以下文章

常见的数据库都有哪些

常用的网络协议都有哪些?

常用的java开发框架都有哪些

Python 常用的标准库以及第三方库都有哪些

Python 常用的标准库以及第三方库都有哪些

一般公司常用的软件测试工具都有哪些?