c#.NET设计系统,数据库的问题

c#.NET设计系统,数据库的问题,第1张

本文将详细介绍如何使用Connection对象连接数据库。对于不同的NET数据提供者,ADONET采用不同的Connection对象连接数据库。这些Connection对象为我们屏蔽了具体的实现细节,并提供了一种统一的实现方法。

Connection类有四种:SqlConnection,OleDbConnection,OdbcConnection和OracleConnection。

SqlConnection类的对象连接SQL Server数据库;OracleConnection 类的对象连接Oracle数据库;

OleDbConnection类的对象连接支持OLE DB的数据库,如Access;而OdbcConnection类的对象连接任何支持ODBC的数据库。与数据库的所有通讯最终都是通过Connection对象来完成的。

SqlConnection类

Connection 用于与数据库“对话”,并由特定提供程序的类(如 SqlConnection)表示。尽管SqlConnection类是针对Sql Server的,但是这个类的许多属性、方法与事件和OleDbConnection及OdbcConnection等类相似。本章将重点讲解SqlConnection特定的属性与方法,其他的Connection类你可以参考相应的帮助文档。

注意:使用不同的Connection对象需要导入不同的命名空间。OleDbConnection的命名空间为SystemDataOleDb。SqlConnection的命名空间为SystemDataSqlClient。OdbcConnection的命名空间为SystemDataOdbc。OracleConnection的命名空间为SystemDataOracleClinet。

SqlConnection属性:

属性 说明

ConnectionString 其返回类型为string,获取或设置用于打开 SQL Server 数据库的字符串。

ConnectionTimeOut 其返回类型为int,获取在尝试建立连接时终止尝试并生成错误之前所等待的时间。

Database 其返回类型为string,获取当前数据库或连接打开后要使用的数据库的名称。

DataSource 其返回类型为string,获取要连接的 SQL Server 实例的名称。

State 其返回类型为ConnectionState,取得当前的连接状态:Broken、Closed、Connecting、Fetching或Open。

ServerVersion 其返回类型为string,获取包含客户端连接的 SQL Server 实例的版本的字符串。

PacketSize 获取用来与 SQL Server 的实例通信的网络数据包的大小(以字节为单位)。这个属性只适用于SqlConnection类型

SqlConnection方法:

方法 说明

Close() 其返回类型为void,关闭与数据库的连接。

CreateCommand() 其返回类型为SqlCommand,创建并返回一个与 SqlConnection 关联的 SqlCommand 对象。

Open() 其返回类型为void,用连接字符串属性指定的属性打开数据库连接

SqlConnection事件:

事件 说明

StateChange 当事件状态更改时发生。 (从 DbConnection 继承。)

InfoMessage 当 SQL Server 返回一个警告或信息性消息时发生。

提示:可以用事件让一个对象以某种方式通知另一对象产生某些事情。例如我们在Windows系统中选择“开始”菜单,一旦单击鼠标时,就发生了一个事件,通知 *** 作系统将“开始”菜单显示出来。

使用SqlConnection对象连接SQL Server数据库

我们可以用SqlConnection()构造函数生成一个新的SqlConnection对象。这个函数是重载的,即我们可以调用构造函数的不同版本。SqlConnection()的构造函数如下表所示:

构造函数 说明

SqlConnection () 初始化 SqlConnection 类的新实例。

SqlConnection (String) 如果给定包含连接字符串的字符串,则初始化 SqlConnection 类的新实例。

假设我们导入了SystemDataSqlClient命名空间,则可以用下列语句生成新的SqlConnection对象:

SqlConnection mySqlConnection = new SqlConnection();

程序代码说明:在上述语法范例的程序代码中,我们通过使用“new“关键字生成了一个新的SqlConnection对象,并且将其命名为mySqlConnection。

现在我们就可以使用如下两种方式连接数据库,即采用集成的Windows验证和使用Sql Server身份验证进行数据库的登录。

集成的Windows身份验证语法范例

string connectionString="server=localhost;database=Northwind;

integrated security=SSPI";

程序代码说明:在上述语法范例的程序代码中,我们设置了一个针对Sql Server数据库的连接字符串。其中server表示运行Sql Server的计算机名,由于在本书中,ASPNET程序和数据库系统是位于同一台计算机的,所以我们可以用localhost取代当前的计算机名。database表示所使用的数据库名,这里设置为Sql Server自带的一个示例数据库--Northwind。由于我们希望采用集成的Windows验证方式,所以设置 integrated security为SSPI即可。

Sql Server 2005中的Windows身份验证模式如下:

注意:在使用集成的Windows验证方式时,并不需要我们输入用户名和口令,而是把登录Windows时输入的用户名和口令传递到Sql Server。然后Sql Server检查用户清单,检查其是否具有访问数据库的权限。而且数据库连接字符串是不区分大小写的。

采用Sql Server身份验证的语法范例

string connectionString = "server=localhost;database=Northwind;uid=sa;pwd=sa";

程序代码说明:在上述语法范例的程序代码中,采用了使用已知的用户名和密码验证进行数据库的登录。uid为指定的数据库用户名,pwd为指定的用户口令。为了安全起见,一般不要在代码中包括用户名和口令,你可以采用前面的集成的Windows验证方式或者对WebConfig文件中的连接字符串加密的方式提高程序的安全性。

Sql Server 2005中的Sql Server身份验证模式如下:

如果你使用其他的数据提供者的话,所产生的连接字符串也具有相类似的形式。例如我们希望以OLE DB的方式连接到一个Oracle数据库,其连接字符串如下:

string connectionString = "data source=localhost;initial catalog=Sales;

use id=sa;password=;provider=MSDAORA";

程序代码说明:在上述语法范例的程序代码中,通过专门针对Oracle数据库的OLE DB提供程序,实现数据库的连接。data source 表示运行Oracle数据库的计算机名,initial catalog表示所使用的数据库名。provider表示使用的OLE DB提供程序为MSDAORA。

Access数据库的连接字符串的形式如下:

string connectionString = "provider=MicrosoftJetOLEDB40;

@”data source=c:\DataSource\Northwindmdb”;

程序代码说明:在上述语法范例的程序代码中,通过专门针对Access数据库的OLE DB提供程序,实现数据库的连接。这使用的的OLE DB提供程序为MicrosoftJetOLEDB40,并且数据库存放在c:\DataSource目录下,其数据库文件为Northwindmdb。

现在我们就可以将数据库连接字符串传人SqlConnection()构造函数,例如:

string connectionString = "server=localhost;database=Northwind;uid=sa;pwd=sa";

SqlConnection mySqlConnection = new SqlConnection(connectionString);

或者写成

SqlConnection mySqlConnection =new SqlConnection(

"server=localhost;database=Northwind;uid=sa;pwd=sa");

在前面的范例中,通过使用“new“关键字生成了一个新的SqlConnection对象。因此我们也可以设置该对象的ConnectionString属性,为其指定一个数据库连接字符串。这和将数据库连接字符串传人SqlConnection()构造函数的功能是一样的。

SqlConnection mySqlConnection = new SqlConnection();

mySqlConnectionConnectionString = "server=localhost;database=Northwind;uid=sa;pwd=sa";

注意:只能在关闭Connection对象时设置ConnectionString属性。

打开和关闭数据库连接

生成Connection对象并将其设置ConnectionString属性设置为数据库连接的相应细节之后,就可以打开数据库连接。为此可以调用Connection对象的Open()方法。其方法如下:

mySqlConnectionOpen();

完成数据库的连接之后,我们可以调用Connection对象的Close()方法关闭数据库连接。例如:

mySqlConnectionClose();

下面是一个显示如何用SqlConnection对象连接Sql Server Northwind数据库的实例程序,并且显示该SqlConnection对象的一些属性。

范例程序代码如下:

01 public partial class _Default : SystemWebUIPage

02 {

03 protected void Page_Load(object sender, EventArgs e)

04 {

05 //建立数据库连接字符串

06 string connectionString = "server=localhost;database=Northwind;

07 integrated security=SSPI";

08 //将连接字符串传入SqlConnection对象的构造函数中

09 SqlConnection mySqlConnection = new SqlConnection(connectionString);

10 try

11 {

12 //打开连接

13 mySqlConnectionOpen();

14 //利用label控件显示mySqlConnection对象的ConnectionString属性

15 lblInfoText = "<b>mySqlConnection对象的ConnectionString属性为:<b>" +

16 mySqlConnectionConnectionString + "<br>";

17 lblInfoText += "<b>mySqlConnection对象的ConnectionTimeout属性为<b>" +

18 mySqlConnectionConnectionTimeout + "<br>";

19 lblInfoText += "<b>mySqlConnection对象的Database属性为<b>" +

20 mySqlConnectionDatabase + "<br>";

21 lblInfoText += "<b>mySqlConnection对象的DataSource属性为<b>" +

22 mySqlConnectionDataSource + "<br>";

23 lblInfoText += "<b>mySqlConnection对象的PacketSize属性为<b>" +

24 mySqlConnectionPacketSize + "<br>";

25 lblInfoText += "<b>mySqlConnection对象的ServerVersion属性为<b>" +

26 mySqlConnectionServerVersion + "<br>";

27 lblInfoText += "<b>mySqlConnection对象的当前状态为<b>" +

28 mySqlConnectionState + "<br>";

29 }

30 catch (Exception err)

31 {

32 lblInfoText = "读取数据库出错";

33 lblInfoText += errMessage;

34 }

35 finally

36 {

37 //关闭与数据库的连接

38 mySqlConnectionClose();

39 lblInfoText += "<br><b>关闭连接后的mySqlConnection对象的状态为:</b>";

40 lblInfoText += mySqlConnectionStateToString();

41 }

42 }

43 }

程序代码说明:在上述范例的程序代码中,我们利用try catch finally对数据库连接进行异常处理。当无法连接数据库时将抛出异常,并显示出错信息,见catch代码块所示。在此程序中,无论是否发生异常,都可以通过finally区块关闭数据库的连接,从而节省计算机资源,提高了程序的效率和可扩展性。

执行结果:

当然,我们还可以采用一种更加简便的方法来实现上述程序的功能。这就是将SqlConnection对象包含到using区块中,这样程序会自动调用Dispose()方法释放SqlConnection对象所占用的系统资源,无需再使用SqlConnection对象的Close()方法。

范例程序代码如下:

01 public partial class _Default : SystemWebUIPage

02 {

03 protected void Page_Load(object sender, EventArgs e)

04 {

05 string connectionString = "server=localhost;database=Northwind;

06 integrated security=SSPI";

07 SqlConnection mySqlConnection = new SqlConnection(connectionString);

08 using (mySqlConnection)

09 {

10 mySqlConnectionOpen();

11 lblInfoText = "<b>mySqlConnection对象的ConnectionString属性为:<b>" +

12 mySqlConnectionConnectionString + "<br>";

13 lblInfoText += "<b>mySqlConnection对象的ConnectionTimeout属性为<b>" +

14 mySqlConnectionConnectionTimeout + "<br>";

15 lblInfoText += "<b>mySqlConnection对象的Database属性为<b>" +

16 mySqlConnectionDatabase + "<br>";

17 lblInfoText += "<b>mySqlConnection对象的DataSource属性为<b>" +

18 mySqlConnectionDataSource + "<br>";

19 lblInfoText += "<b>mySqlConnection对象的PacketSize属性为<b>" +

20 mySqlConnectionPacketSize + "<br>";

21 lblInfoText += "<b>mySqlConnection对象的ServerVersion属性为<b>" +

22 mySqlConnectionServerVersion + "<br>";

23 lblInfoText += "<b>mySqlConnection对象的当前状态为<b>"+

24 mySqlConnectionState + "<br>";

25 }

26 lblInfoText += "<br><b>关闭连接后的mySqlConnection对象的状态为:</b>";

27 lblInfoText += mySqlConnectionStateToString();

28 }

29 }

程序代码说明:在上述范例的程序代码中,采用using(mySqlConnection)的形式使得代码更加简洁,并且其最大的优点就是无需编写finally区块代码,可以自动关闭与数据库的连接。

连接池

打开与关闭数据库都是比较耗时的。为此,ADONET自动将数据库连接存放在连接池中。连接池可以大幅度提高程序的性能和效率,因为我们不必等待建立全新的数据库连接过程,而是直接利用现成的数据库连接。注意,利用Close()方法关闭连接时,并不是实际关闭连接,而是将连接标为未用,放在连接池中,准备下一次复用。

如果在连接字符串中提供相同的细节,即相同的数据库,用户名,密码等等,则可以直接取得并返回池中的连接。然后可以用这个连接访问数据库。

使用SqlConnection对象时,可以在连接字符串中指定max pool size,表示连接池允许的最大连接数(默认为100),也可以指定min pool size表示连接池允许的最小连接数(默认为0)。下面的代码指定了SqlConnection对象的max pool size为10,min pool size为5。

SqlConnection mySqlConnection = new SqlConnection("server=localhost;database=Northwind;

integrated security=SSPI;"+"max pool size=10;min pool size=5");

程序代码说明:在上述范例的程序代码中,程序最初在池中生成5个SqlConnection对象。池中可以存储最多10个SqlConnection对象。如果要打开新的SqlConnection对象时,池中的对象全部都在使用中,则请求要等待一个SqlConnection对象关闭,然后才可以使用新的SqlConnection对象。如果请求等待时间超过ConnectionTimeout属性指定的秒数,则会抛出异常。

下面通过一个程序来显示连接池的性能优势。在应用此程序过程我们要先引用SystemDataSqlClinet和SystemText命名空间。

范例程序代码如下:

01 public partial class _Default : SystemWebUIPage

02 {

03 protected void Page_Load(object sender, EventArgs e)

04 {

05 //设置连接池的最大连接数为5,最小为1

06 SqlConnection mySqlConnection =new SqlConnection(

07 "server=localhost;database=Northwind;integrated security=SSPI;"+

08 "max pool size=5;min pool size=1");

09 //新建一个StringBuilder对象

10 StringBuilder htmStr = new StringBuilder("");

11 for (int count = 1; count <= 5; count++)

12 {

13 //使用Append()方法追加字符串到StringBuilder对象的结尾处

14 htmStrAppend("连接对象 "+count);

15 htmStrAppend("<br>");

16 //设置一个连接的开始时间

17 DateTime start = DateTimeNow;

18 mySqlConnectionOpen();

19 //连接所用的时间

20 TimeSpan timeTaken = DateTimeNow - start;

21 htmStrAppend("连接时间为 "+timeTakenMilliseconds+"毫秒");

22 htmStrAppend("<br>");

23 htmStrAppend("mySqlConnection对象的状态为" + mySqlConnectionState);

24 htmStrAppend("<br>");

25 mySqlConnectionClose();

26 }

27 //将StringBuilder对象的包含的字符串在label控件中显示出来

28 lblInfoText = htmStrToString();

29 }

30 }

程序代码说明:在上述范例的程序代码中,我们将在连接池中重复5次打开一个SqlConnection对象,DateTimeNow表示当前的时间。timeTaken表示从连接开始到打开连接所用的时间间隔。可以看出,打开第一个连接的时间比打开后续连接的时间要长,因为第一个连接要实际连接数据库。被关闭之后,这个连接存放在连接池中。再次打开连接时,只要从池中直接读取即可,速度非常快。

提示:String 对象是不可改变的。每次使用 SystemString 类中的方法之一时,都要在内存中创建一个新的字符串对象,这就需要为该新对象分配新的空间。在需要对字符串执行重复修改的情况下,与创建新的 String 对象相关的系统开销可能会非常昂贵。如果要修改字符串而不创建新的对象,则可以使用 SystemTextStringBuilder 类。例如,当在一个循环中将许多字符串连接在一起时,使用 StringBuilder 类可以提升性能。Append 方法可用来将文本或对象的字符串表示形式添加到由当前 StringBuilder 对象表示的字符串的结尾处。

在ASPNET 20中,使用了一种在运行时解析为连接字符串值的新的声明性表达式语法,按名称引用数据库连接字符串。连接字符串本身存储在 Webconfig 文件中的 <connectionStrings> 配置节下面,以便易于在单个位置为应用程序中的所有页进行维护。

范例程序代码如下:

<xml version="10">

<configuration>

<connectionStrings>

<add name="Pubs" connectionString="Server=localhost;

Integrated Security=True;Database=pubs;Persist Security Info=True"

providerName="SystemDataSqlClient" />

<add name="Northwind" connectionString="Server=localhost;

Integrated Security=True;Database=Northwind;Persist Security Info=True"

providerName="SystemDataSqlClient" />

</connectionStrings>

<systemweb>

<pages styleSheetTheme="Default"/>

</systemweb>

</configuration>

程序代码说明:在上述范例的程序代码中,我们在WebConfig文件中的<connectionStrings> 配置节点下面设置了两个数据库连接字符串,分别指向pubs和Northwind两个示例数据库。注意,在20中引进了数据源控件,例如SqlDataSource 控件,我们可以将SqlDataSource 控件的 ConnectionString 属性被设置为表达式 <%$ ConnectionStrings:Pubs %>,该表达式在运行时由 ASPNET 分析器解析为连接字符串。还可以为SqlDataSource 的 ProviderName 属性指定一个表达式,例如 <%$ ConnectionStrings:PubsProviderName %>。其具体的用法和新特征将在以后的章节进行详细的介绍。现在有个基础的了解即可。

当然,我们也可以用下面的方式从配置文件直接读取数据库连接字符串。首先我们需要引用using SystemWebConfiguration命名空间,该命名空间包含用于设置 ASPNET 配置的类。

string connectionString =ConfigurationManagerConnectionStrings["Northwind"]ConnectionString;

程序代码说明:在上述范例的程序代码中,我们可以利用ConnectionStrings["Northwind"]读取相应的Northwind字符串。同理以可以利用ConnectionStrings["Pubs"]读取相应的Pubs字符串。

myspl。

MySQL 是最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Databasebr。其特点如下:据以表格的形式出现,每行为各种记录名称,每列为记录名称所对应的数据域,许多的行和列组成一张表单,若干的表单组成database。

oracle数据库基本语句

甲骨文公司,全称甲骨文股份有限公司(甲骨文软件系统有限公司),是全球最大的企业级软件公司,总部位于美国加利福尼亚州的红木滩。下面是我整理的关于oracle数据库基本语句,欢迎大家参考!

1登陆SPLPLUS

[username/password] [@server] as [sysdba|sysoper]

eg system/password or connect sys/password as sysdba

2查看登录用户

show user

dba_users

desc dba_users//展示表结构

select username from dba_users;

3解锁用户

alter user username account unlock

4表空间

数据库--->表空间--->数据文件

表空间分类:

永久表空间: 表、视图,永久保存

临时表空间: *** 作当中的过程,过程结束即被释放

UNDO表空间: 保存事务所修改数据的旧址,就是被修改之前的数据,用于回滚

5创建表空间

create [temporary] tablespace tablespace_name tempfile|datafile 'xxdbf' size xx

永久表空间

create tablespace test1_tablespace

datafile 'testlfiledbf' size 10m;

临时表空间

create temporary temptest1_tablespace

tempfile 'tempfile1dbf' size 10m;

改变表空间状态

alter tablespace tablespacename offline|online;联机||脱机

alter tablespace tablespacename read only|read write;

6增加/删除数据文件

增加

alter tablespace tablespace_name add datafile 'xxdbf' size xx;

删除

alter tablespace tablespace_name drop datafile 'xxdbf';

7表

(1)基本存储结构

(2)二维结构

(3)行和列

8数据类型

字符型

char(n) n<=2000 补充为n位

nchar(n) n<=1000

varchar2(n) n<=4000

nvarchar2(n)n<=2000

数值型

number(p,s) p有效数字,s小数点后的位数

float(n)

日期型

data

timestamp

其他类型

blob 4GB二进制

clob 4GB字符串

9管理表

创建表

create table table_name

(

colimn_name datatype,

) ;

数据库语言的目标

要说清这个目标,先要理解数据库是做什么的。

数据库这个软件,名字中有个“库”字,会让人觉得它主要是为了存储的。其实不然,数据库实现的重要功能有两条:计算、事务!也就是我们常说的 OLAP 和 OLTP,数据库的存储都是为这两件事服务的,单纯的存储并不是数据库的目标。

我们知道,SQL 是目前数据库的主流语言。那么,用 SQL 做这两件事是不是很方便呢?

事务类功能主要解决数据在写入和读出时要保持的一致性,实现这件事的难度并不小,但对于应用程序的接口却非常简单,用于 *** 纵数据库读写的代码也很简单。如果假定目前关系数据库的逻辑存储模式是合理的(也就是用数据表和记录来存储数据,其合理性与否是另一个复杂问题,不在这里展开了),那么 SQL 在描述事务类功能时没什么大问题,因为并不需要描述多复杂的动作,复杂性都在数据库内部解决了。

但计算类功能却不一样了。

这里说的计算是个更广泛的概念,并不只是简单的加加减减,查找、关联都可以看成是某种计算。

什么样的计算体系才算好呢?

还是两条:写着简单、跑得快。

写着简单,很好理解,就是让程序员很快能写出来代码来,这样单位时间内可以完成更多的工作;跑得快就更容易理解,我们当然希望更短时间内获得计算结果。

其实 SQL 中的 Q 就是查询的意思,发明它的初衷主要是为了做查询(也就是计算),这才是 SQL 的主要目标。然而,SQL 在描述计算任务时,却很难说是很胜任的。

SQL为什么不行

先看写着简单的问题。

SQL 写出来很象英语,有些查询可以当英语来读和写(网上多得很,就不举例了),这应当算是满足写着简单这一条了吧。

且慢!我们在教科书上看到的 SQL 经常只有两三行,这些 SQL 确实算是写着简单的,但如果我们尝试一些稍复杂化的问题呢?

这是一个其实还不算很复杂的例子:计算一支股票最长连续上涨了多少天?用 SQL 写出来是这样的:

selectmax(consecutive_day)from(selectcount() (consecutive_dayfrom(selectsum(rise_mark) over(orderbytrade_date) days_no_gainfrom(selecttrade_date,case when closing_price>lag(closing_price) over(order by trade_date)then 0 else 1 END rise_markfrom stock_price ) )group by days\_no\_gain)

这个语句的工作原理就不解释了,反正有点绕,同学们可以自己尝试一下。

这是润乾公司的招聘考题,通过率不足 20%;因为太难,后来被改成另一种方式:把 SQL 语句写出来让应聘者解释它在算什么,通过率依然不高。

这说明什么?说明情况稍有复杂,SQL 就变得即难懂又难写!

再看跑得快的问题,还是一个经常拿出来的简单例子:1 亿条数据中取前 10 名。这个任务用 SQL 写出来并不复杂:

SELECTTOP 10x FROMT ORDERBYx DESC

但是,这个语句对应的执行逻辑是先对所有数据进行大排序,然后再取出前 10 个,后面的不要了。大家知道,排序是一个很慢的动作,会多次遍历数据,如果数据量大到内存装不下,那还需要外存做缓存,性能还会进一步急剧下降。如果严格按这句 SQL 体现的逻辑去执行,这个运算无论如何是跑不快的。然而,很多程序员都知道这个运算并不需要大排序,也用不着外存缓存,一次遍历用一点点内存就可以完成,也就是存在更高性能的算法。可惜的是,用 SQL 却写不出这样的算法,只能寄希望于数据库的优化器足够聪明,能把这句 SQL 转换成高性能算法执行,但情况复杂时数据库的优化器也未必靠谱。

看样子,SQL 在这两方面做得都不够好。这两个并不复杂的问题都是这样,现实中数千行的 SQL 代码中,这种难写且跑不快的情况比比皆是。

为什么 SQL 不行呢?

要回答这个问题,我们要分析一下用程序代码实现计算到底是在干什么。

本质上讲,编写程序的过程,就是把解决问题的思路翻译成计算机可执行的精确化形式语言的过程。举例来说,就象小学生解应用题,分析问题想出解法之后,还要列出四则运算表达式。用程序计算也是一样,不仅要想出解决问题的方法,还要把解法翻译成计算机能理解执行的动作才算完成。

用于描述计算方法的形式语言,其核心在于所采用的代数体系。所谓代数体系,简单说就是一些数据类型和其上的运算规则,比如小学学到的算术,就是整数和加减乘除运算。有了这套东西,我们就能把想做的运算用这个代数体系约定的符号写出来,也就是代码,然后计算机就可以执行了。

如果这个代数体系设计时考虑不周到,提供的数据类型和运算不方便,那就会导致描述算法非常困难。这时候会发生一个怪现象:翻译解法到代码的难度远远超过解决问题本身。

举个例子,我们从小学习用阿拉伯数字做日常计算,做加减乘除都很方便,所有人都天经地义认为数值运算就该是这样的。其实未必!估计很多人都知道还有一种叫做罗马数字的东西,你知道用罗马数字该怎么做加减乘除吗?古罗马人又是如何上街买菜的?

代码难写很大程度是代数的问题。

再看跑不快的原因。

软件没办法改变硬件的性能,CPU 和硬盘该多快就是多快。不过,我们可以设计出低复杂度的算法,也就是计算量更小的算法,这样计算机执行的动作变少,自然也就会快了。但是,光想出算法还不够,还要把这个算法用某种形式语言写得出来才行,否则计算机不会执行。而且,写起来还要比较简单,都要写很长很麻烦,也没有人会去用。所以呢,对于程序来讲,跑得快和写着简单其实是同一个问题,背后还是这个形式语言采用的代数的问题。如果这个代数不好,就会导致高性能算法很难实现甚至实现不了,也就没办法跑得快了。就象上面说的,用 SQL 写不出我们期望的小内存单次遍历算法,能不能跑得快就只能寄希望于优化器。

我们再做个类比:

上过小学的同学大概都知道高斯计算 1+2+3+…+100 的小故事。普通人就是一步步地硬加 100 次,高斯小朋友很聪明,发现 1+100=101、2+99=101、…、50+51=101,结果是 50 乘 101,很快算完回家午饭了。

听过这个故事,我们都会感慨高斯很聪明,能想到这么巧妙的办法,即简单又迅速。这没有错,但是,大家容易忽略一点:在高斯的时代,人类的算术体系(也是一个代数)中已经有了乘法!象前面所说,我们从小学习四则运算,会觉得乘法是理所当然的,然而并不是!乘法是后于加法被发明出来的。如果高斯的年代还没有乘法,即使有聪明的高斯,也没办法快速解决这个问题。

目前主流数据库是关系数据库,之所以这么叫,是因为它的数学基础被称为关系代数,SQL 也就是关系代数理论上发展出来的形式语言。

现在我们能回答,为什么 SQL 在期望的两个方面做得不够好?问题出在关系代数上,关系代数就像一个只有加法还没发明乘法的算术体系,很多事做不好是必然的。

关系代数已经发明五十年了,五十年前的应用需求以及硬件环境,和今天比的差异是很巨大了,继续延用五十年前的理论来解决今天的问题,听着就感觉太陈旧了?然而现实就是这样,由于存量用户太多,而且也还没有成熟的新技术出现,基于关系代数的 SQL,今天仍然是最重要的数据库语言。虽然这几十年来也有一些改进完善,但根子并没有变,面对当代的复杂需求和硬件环境,SQL 不胜任也是情理之中的事。

而且,不幸的是,这个问题是理论上的,在工程上无论如何优化也无济于事,只能有限改善,不能根除。不过,绝大部分的数据库开发者并不会想到这一层,或者说为了照顾存量用户的兼容性,也没打算想到这一层。于是,主流数据库界一直在这个圈圈里打转转。

SPL为什么能行

那么该怎样让计算写着更简单、跑得更快呢?

发明新的代数!有“乘法”的代数。在其基础上再设计新的语言。

这就是 SPL 的由来。它的理论基础不再是关系代数,称为离散数据集。基于这个新代数设计的形式语言,起名为SPL(Structured Process Language)。

SPL 针对 SQL 的不足(更确切地说法是,离散数据集针对关系代数的各种缺陷)进行了革新。SPL 重新定义了并扩展许多结构化数据中的运算,增加了离散性、强化了有序计算、实现了彻底的集合化、支持对象引用、提倡分步运算。

限于篇幅,这里不能介绍 SPL(离散数据集)的全貌。我们在这里列举 SPL(离散数据集)针对 SQL(关系代数)的部分差异化改进:

游离记录

离散数据集中的记录是一种基本数据类型,它可以不依赖于数据表而独立存在。数据表是记录构成的集合,而构成某个数据表的记录还可以用于构成其它数据表。比如过滤运算就是用原数据表中满足条件的记录构成新数据表,这样,无论空间占用还是运算性能都更有优势。

关系代数没有可运算的数据类型来表示记录,单记录实际上是只有一行的数据表,不同数据表中的记录也不能共享。比如,过滤运算时会复制出新记录来构成新数据表,空间和时间成本都变大。

特别地,因为有游离记录,离散数据集允许记录的字段取值是某个记录,这样可以更方便地实现外键连接。

有序性

关系代数是基于无序集合设计的,集合成员没有序号的概念,也没有提供定位计算以及相邻引用的机制。SQL 实践时在工程上做了一些局部完善,使得现代 SQL 能方便地进行一部分有序运算。

离散数据集中的集合是有序的,集合成员都有序号的概念,可以用序号访问成员,并定义了定位运算以返回成员在集合中的序号。离散数据集提供了符号以在集合运算中实现相邻引用,并支持针对集合中某个序号位置进行计算。

有序运算很常见,却一直是 SQL 的困难问题,即使在有了窗口函数后仍然很繁琐。SPL 则大大改善了这个局面,前面那个股票上涨的例子就能说明问题。

离散性与集合化

关系代数中定义了丰富的集合运算,即能将集合作为整体参加运算,比如聚合、分组等。这是 SQL 比 Java 等高级语言更为方便的地方。

但关系代数的离散性非常差,没有游离记录。而 Java 等高级语言在这方面则没有问题。

离散数据集则相当于将离散性和集合化结合起来了,既有集合数据类型及相关的运算,也有集合成员游离在集合之外单独运算或再组成其它集合。可以说 SPL 集中了 SQL 和 Java 两者的优势。

有序运算是典型的离散性与集合化的结合场景。次序的概念只有在集合中才有意义,单个成员无所谓次序,这里体现了集合化;而有序计算又需要针对某个成员及其相邻成员进行计算,需要离散性。

在离散性的支持下才能获得更彻底的集合化,才能解决诸如有序计算类型的问题。

离散数据集是即有离散性又有集合化的代数体系,关系代数只有集合化。

分组理解

分组运算的本意是将一个大集合按某种规则拆成若干个子集合,关系代数中没有数据类型能够表示集合的集合,于是强迫在分组后做聚合运算。

离散数据集中允许集合的集合,可以表示合理的分组运算结果,分组和分组后的聚合被拆分成相互独立的两步运算,这样可以针对分组子集再进行更复杂的运算。

关系代数中只有一种等值分组,即按分组键值划分集合,等值分组是个完全划分。

离散数据集认为任何拆分大集合的方法都是分组运算,除了常规的等值分组外,还提供了与有序性结合的有序分组,以及可能得到不完全划分结果的对位分组。

聚合理解

关系代数中没有显式的集合数据类型,聚合计算的结果都是单值,分组后的聚合运算也是这样,只有 SUM、COUNT、MAX、MIN 等几种。特别地,关系代数无法把 TOPN 运算看成是聚合,针对全集的 TOPN 只能在输出结果集时排序后取前 N 条,而针对分组子集则很难做到 TOPN,需要转变思路拼出序号才能完成。

离散数据集提倡普遍集合,聚合运算的结果不一定是单值,仍然可能是个集合。在离散数据集中,TOPN 运算和 SUM、COUNT 这些是地位等同的,即可以针对全集也可以针对分组子集。

SPL 把 TOPN 理解成聚合运算后,在工程实现时还可以避免全量数据的排序,从而获得高性能。而 SQL 的 TOPN 总是伴随 ORDER BY 动作,理论上需要大排序才能实现,需要寄希望于数据库在工程实现时做优化。

有序支持的高性能

离散数据集特别强调有序集合,利用有序的特征可以实施很多高性能算法。这是基于无序集合的关系代数无能为力的,只能寄希望于工程上的优化。

下面是部分利用有序特征后可以实施的低复杂度运算:

1) 数据表对主键有序,相当于天然有一个索引。对键字段的过滤经常可以快速定位,以减少外存遍历量。随机按键值取数时也可以用二分法定位,在同时针对多个键值取数时还能重复利用索引信息。

2) 通常的分组运算是用 HASH 算法实现的,如果我们确定地知道数据对分组键值有序,则可以只做相邻对比,避免计算 HASH 值,也不会有 HASH 冲突的问题,而且非常容易并行。

3) 数据表对键有序,两个大表之间对位连接可以执行更高性能的归并算法,只要对数据遍历一次,不必缓存,对内存占用很小;而传统的 HASH 值分堆方法不仅比较复杂度高,需要较大内存并做外部缓存,还可能因 HASH 函数不当而造成二次 HASH 再缓存。

4) 大表作为外键表的连接。事实表小时,可以利用外键表有序,快速从中取出关联键值对应的数据实现连接,不需要做 HASH 分堆动作。事实表也很大时,可以将外键表用分位点分成多个逻辑段,再将事实表按逻辑段进行分堆,这样只需要对一个表做分堆,而且分堆过程中不会出现 HASH 分堆时的可能出现的二次分堆,计算复杂度能大幅下降。

其中 3 和 4 利用了离散数据集对连接运算的改造,如果仍然延用关系代数的定义(可能产生多对多),则很难实现这种低复杂的算法。

除了理论上的差异, SPL 还有许多工程层面的优势,比如更易于编写并行代码、大内存预关联提高外键连接性能等、特有的列存机制以支持随意分段并行等。

再把前面的问题用 SPL 重写一遍有个直接感受。

一支股票最长连续上涨多少天:

stock_pricesort(trade_date)group@o(closing_price

计算思路和前面的 SQL 相同,但因为引入了有序性后,表达起来容易多了,不再绕了。

1 亿条数据中取前 10 名:

Tgroups(;top(-10,x))

SPL 有更丰富的集合数据类型,容易描述单次遍历上实施简单聚合的高效算法,不涉及大排序动作。

这里还有更多 SPL 代码以体现其思路及大数据算法:

重磅!开源SPL交流群成立了

简单好用的SPL开源啦!

为了给感兴趣的小伙伴们提供一个相互交流的平台,

特地开通了交流群(群完全免费,不广告不卖课)

需要进群的朋友,可长按扫描下方二维码

我的方法一般是用phpmyadmin:

这个是个可以在浏览器里 *** 作mysql的图形化软件,你先用phpmyadmin把那个别人的数据库导出为databasespl文件,然后在把该文件导入自己的数据库,十分简单,而且这个软件是中文界面的,摸索下就会的。

以上就是关于c# .NET设计系统,数据库的问题全部的内容,包括:c# .NET设计系统,数据库的问题、超过一百万行的表用什么数据库、oracle数据库基本语句等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/9717821.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-01
下一篇 2023-05-01

发表评论

登录后才能评论

评论列表(0条)

保存