大型数据库设计原则

大型数据库设计原则,第1张

一个好的数据库产品不等于就有一个好的应用系统 如果不能设计一个合理的数据库模型 不仅会增加客户端和服务器段程序的编程和维护的难度 而且将会影响系统实际运行的性能 一般来讲 在一个MIS系统分析 设计 测试和试运行阶段 因为数据量较小 设计人员和测试人员往往只注意到功能的实现 而很难注意到性能的薄弱之处 等到系统投入实际运行一段时间后 才发现系统的性能在降低 这时再来考虑提高系统性能则要花费更多的人力物力 而整个系统也不可避免的形成了一个打补丁工程 笔者依据多年来设计和使用数据库的经验 提出以下一些设计准则 供同仁们参考

命名的规范

不同的数据库产品对对象的命名有不同的要求 因此 数据库中的各种对象的命名 后台程序的代码编写应采用大小写敏感的形式 各种对象命名长度不要超过 个字符 这样便于应用系统适应不同的数据库

游标(Cursor)的慎用

游标提供了对特定集合中逐行扫描的手段 一般使用游标逐行遍历数据 根据取出的数据不同条件进行不同的 *** 作 尤其对多表和大表定义的游标(大的数据集合)循环很容易使程序进入一个漫长的等特甚至死机 笔者在某市《住房公积金管理系统》进行日终帐户滚积数计息处理时 对一个 万个帐户的游标处理导致程序进入了一个无限期的等特(后经测算需 个小时才能完成)(硬件环境 Alpha/ Mram Sco Unix Sybase ) 后根据不同的条件改成用不同的UPDATE语句得以在二十分钟之内完成 示例如下

Declare Mycursor cursor for select  count_no from COUNT

Open Mycursor

Fetch Mycursor into @vcount_no

While (@@sqlstatus= )

Begin

If  @vcount_no=   条件

*** 作

If  @vcount_no=   条件

*** 作

Fetch Mycursor into @vcount_no

End

改为

Update COUNT set  *** 作 for 条件

Update COUNT set  *** 作 for 条件

在有些场合 有时也非得使用游标 此时也可考虑将符合条件的数据行转入临时表中 再对临时表定义游标进行 *** 作 可时性能得到明显提高 笔者在某地市〈电信收费系统〉数据库后台程序设计中 对一个表( 万行中符合条件的 多行数据)进行游标 *** 作(硬件环境 PC服务器 PII Mram NT Ms Sqlserver ) 示例如下

Create #tmp   / 定义临时表 /

(字段

字段

)

Insert into #tmp select from TOTAL where

条件  / TOTAL中 万行 符合条件只有几十行 /

Declare Mycursor cursor for select from #tmp

/对临时表定义游标/

索引(Index)的使用原则

创建索引一般有以下两个目的 维护被索引列的唯一性和提供快速访问表中数据的策略 大型数据库有两种索引即簇索引和非簇索引 一个没有簇索引的表是按堆结构存储数据 所有的数据均添加在表的尾部 而建立了簇索引的表 其数据在物理上会按照簇索引键的顺序存储 一个表只允许有一个簇索引 因此 根据B树结构 可以理解添加任何一种索引均能提高按索引列查询的速度 但会降低插入 更新 删除 *** 作的性能 尤其是当填充因子(Fill Factor)较大时 所以对索引较多的表进行频繁的插入 更新 删除 *** 作 建表和索引时因设置较小的填充因子 以便在各数据页中留下较多的自由空间 减少页分割及重新组织的工作

数据的一致性和完整性

为了保证数据库的一致性和完整性 设计人员往往会设计过多的表间关联(Relation) 尽可能的降低数据的冗余 表间关联是一种强制性措施 建立后 对父表(Parent Table)和子表(Child Table)的插入 更新 删除 *** 作均要占用系统的开销 另外 最好不要用Identify 属性字段作为主键与子表关联 如果数据冗余低 数据的完整性容易得到保证 但增加了表间连接查询的 *** 作 为了提高系统的响应时间 合理的数据冗余也是必要的 使用规则(Rule)和约束(Check)来防止系统 *** 作人员误输入造成数据的错误是设计人员的另一种常用手段 但是 不必要的规则和约束也会占用系统的不必要开销 需要注意的是 约束对数据的有效性验证要比规则快 所有这些 设计人员在设计阶段应根据系统 *** 作的类型 频度加以均衡考虑

事务的陷阱

事务是在一次性完成的一组 *** 作 虽然这些 *** 作是单个的 *** 作 SQL Server能够保证这组 *** 作要么全部都完成 要么一点都不做 正是大型数据库的这一特性 使得数据的完整性得到了极大的保证

众所周知 SQL Server为每个独立的SQL语句都提供了隐含的事务控制 使得每个DML的数据 *** 作得以完整提交或回滚 但是SQL Server还提供了显式事务控制语句

BEGIN TRANSACTION 开始一个事务

MIT TRANSACTION 提交一个事务

ROLLBACK TRANSACTION 回滚一个事务

事务可以嵌套 可以通过全局变量@@trancount检索到连接的事务处理嵌套层次 需要加以特别注意并且极容易使编程人员犯错误的是 每个显示或隐含的事物开始都使得该变量加 每个事务的提交使该变量减 每个事务的回滚都会使得该变量置 而只有当该变量为 时的事务提交(最后一个提交语句时) 这时才把物理数据写入磁盘

数据库性能调整

在计算机硬件配置和网络设计确定的情况下 影响到应用系统性能的因素不外乎为数据库性能和客户端程序设计 而大多数数据库设计员采用两步法进行数据库设计 首先进行逻辑设计 而后进行物理设计 数据库逻辑设计去除了所有冗余数据 提高了数据吞吐速度 保证了数据的完整性 清楚地表达数据元素之间的关系 而对于多表之间的关联查询(尤其是大数据表)时 其性能将会降低 同时也提高了客 户端程序的编程难度 因此 物理设计需折衷考虑 根据业务规则 确定对关联表的数据量大小 数据项的访问频度 对此类数据表频繁的关联查询应适当提高数据冗余设计

数据类型的选择

数据类型的合理选择对于数据库的性能和 *** 作具有很大的影响 有关这方面的书籍也有不少的阐述 这里主要介绍几点经验

Identify字段不要作为表的主键与其它表关联 这将会影响到该表的数据迁移

Text 和Image字段属指针型数据 主要用来存放二进制大型对象(BLOB) 这类数据的 *** 作相比其它数据类型较慢 因此要避开使用

日期型字段的优点是有众多的日期函数支持 因此 在日期的大小比较 加减 *** 作上非常简单 但是 在按照日期作为条件的查询 *** 作也要用函数 相比其它数据类型速度上就慢许多 因为用函数作为查询的条件时 服务器无法用先进的性能策略来优化查询而只能进行表扫描遍历每行

例如 要从DATA_TAB 中(其中有一个名为DATE的日期字段)查询 年的所有记录

lishixinzhi/Article/program/Oracle/201311/17929

三级模式结构:外模式、模式和内模式

一、模式(schema)

定义:也称逻辑模式,是数据库中全体数据的逻辑结构和特征的描述,是所有用户的公共数据视图

理解:

一个数据库只有一个模式;

是数据库数据在逻辑级上的视图;

数据库模式以某一种数据模型为基础;

定义模式时不仅要定义数据的逻辑结构(如数据记录由哪些数据项构成,数据项的名字、类型、取值范围等),而且要定义与数据有关的安全性、完整性要求,定义这些数据之间的联系。

二、外模式(external

schema)

定义:也称子模式(subschema)或用户模式,是数据库用户(包括应用程序员和最终用户)能够看见和使用的局部数据的逻辑结构和特征的描述,是数据库用户的数据视图,是与某一应用有关的数据的逻辑表示。

理解:

一个数据库可以有多个外模式;

外模式就是用户视图;

外模式是保证数据安全性的一个有力措施。

三、内模式(internal

schema)

定义:也称存储模式(storage

schema),它是数据物理结构和存储方式的描述,是数据在数据库内部的表示方式(例如,记录的存储方式是顺序存储、按照b树结构存储还是按hash方法存储;索引按照什么方式组织;数据是否压缩存储,是否加密;数据的存储记录结构有何规定)。

理解:

一个数据库只有一个内模式;

一个表可能由多个文件组成,如:数据文件、索引文件。

它是数据库管理系统(dbms)对数据库中数据进行有效组织和管理的方法

其目的有:

为了减少数据冗余,实现数据共享;

为了提高存取效率,改善性能。

数据库系统的三级模式结构是指数据库系统是由模式、外模式和内模式三级构成的。

(1)模式模式也称逻辑模式或概念模式,是数据库中全体数据的逻辑结构和特征的描述,是所有用户的公共数据视图。

模式实际上是数据库数据在逻辑级上的视图。一个数据库只有一个模式。定义模式时不仅要定义数据的逻辑结构,而且要定义数据之间的联系,定义与数据有关的安全性、完整性要求。

(2)外模式外模式也称用户模式,它是数据库用户能够看见和使用的局部数据的逻辑结构和特征的描述,是数据库用户的数据视图,是与某一应用有关的数据的逻辑表示。外模式通常是模式的子集。一个数据库可以有多个外模式。应用程序都是和外模式打交道的。外模式是保证数据库安全性的一个有力措施。每个用户只能看见和访问所对应的外模式中的数据,数据库中的其余数据对他们是不可见的。

(3)内模式内模式也称存储模式,一个数据库只有一个内模式。它是数据物理结构和存储方式的描述,是数据在数据库内部的表示方式。例如,记录的存储方式是顺序结构存储还是B树结构存储;索引按什么方式组织;数据是否压缩,是否加密;数据的存储记录结构有何规定等。

三级结构的组织形式称为数据库的体系结构或数据抽象的三个级别。这个结构是于1975年在美国ANSI/X3/SPARC(美国国家标准协会的计算机与信息处理委员会中的标准计划与需求委员会)数据库小组的报告中提出的。

1141三级数据视图

数据抽象的三个级别又称为三级数据视图,是不同层次用户(人员)从不同角度所看到的数据组织形式。

(1) 外部视图 第一层的数据组织形式是面向应用的,是应用程序员开发应用程序时所使用的数据组织形式,是应用程序员所看到的数据的逻辑结构,是用户数据视图,称为外部视图。外部视图可有多个。这一层的最大特点是以各类用户的需求为出发点,构造满足其需求的最佳逻辑结构。

(2) 全局视图 第二层的数据组织形式是面向全局应用的,是全局数据的组织形式,是数据库管理人员所看到的全体数据的逻辑组织形式,称为全局视图,全局视图仅有一个。这一层的特点是对全局应用最佳的逻辑结构形式。

(3) 存储视图 第三层的数据组织形式是面向存储的,是按照物理存储最优的策略所组织形式,是系统维护人员所看到的数据结构,称为存储视图。存储视图只有一个。这一层的特点是物理存储最佳的结构形式。

外部视图是全局视图的逻辑子集,全局视图是外部视图的逻辑汇总和综合,存储视图是全局视图的具体实现。三级视图之间的联系由二级映射实现。外部视图和全局视图之间的映射称为逻辑映射,全局视图和存储视图之间的映射称为物理映射。

1142 三级模式

三级视图是用图、表等形式描述的,具有简单、直观的优点。但是,这种形式目前还不能被计算机直接识别。为了在计算机系统中实现数据的三级组织形式,必须用计算机可以识别的语言对其进行描述。DBMS提供了这种数据描述语言(Data Description Language 简记为DDL)。我们称用DDL精确定义数据视图的程序为模式(Scheme)。与三级视图对应的是三级模式。

(1) 子模式定义外部视图的模式称外模式,也称子模式。它由对用户数据文件的逻辑结构描述以及和全局视图中文件的对应关系的描述组成,用DBMS提供的子模式DDL定义。一个子模式可以由多个用户共享,而一个用户只能使用一个子模式。

(2) 模式  定义全局视图的模式称逻辑模式,简称模式。它由对全局视图中全体数据文件的逻辑结构描述以及和存储视图中文件的对应关系的描述组成,用DBMS提供的模式DDL定义。逻辑结构的描述包括记录的型(组成记录的数据项名、类型、取值范围等),还有记录之间的联系,数据的完整性、安全保密要求等。

(3) 内模式  定义存储视图的模式称内模式,又称物理模式。它由对存储视图中全体数据文件的存储结构的描述和对存储介质参数的描述组成,用DBMS提供的内模式DDL定义。存储结构的描述包括记录值的存储方式(顺序存储、hash方法、B树结构等),索引的组织方式等。

三级模式的结构如图18所示。

三级模式所描述的仅仅是数据的组织框架,而不是数据本身。在内模式这个框架填上具体数据就构成物理数据库,它是外部存储器上真实存在的数据集合。模式框架下的数据集合是概念数据库,它仅是物理数据库的逻辑映像。子模式框架下的数据集合是用户数据库,它是概念数据库的逻辑子集。

Log File物理结构

从 ib_logfile0和 ib_logfile1这两个文件的物理结构可以看出,在Log Header部分还是有些许差异的, ib_logfile0会多一些额外的信息,主要是checkpoint信息。

并且每个Block的单位是512字节,对应到磁盘每个扇区也是512字节,因此redo log写磁盘是原子写,保证能够写成功,而不像index page一样需要double write来保证安全写入。

我们依次从上到下来看每个Block的结构

Log File Header Block

Log Goup ID,可能会配置多个redo组,每个组对应一个id,当前都是0,占用4字节

Start LSN,这个redo log文件开始日志的lsn,占用8字节

Log File Number,总是为0,占用4字节

Created By,备份程序所占用的字节数,占用32字节

另外在ib_logfile0中会有两个checkpoint block,分别是 LOG_CHECKPOINT_1/ LOG_CHECKPOINT_2,两个记录InnoDB Checkpoint信息的字段,分别从文件头的第二个和第四个block开始记录,并且只在每组log的第一个文件中存在,组内其他文件虽然没有checkpoint相关信息,但是也会预留相应的空间出来。这里为什么有两个checkpoint的呢?原因是设计为交替写入,避免因为介质失败而导致无法找到可用的checkpoint的情况。

Log blocks

log block结构分为日志头段、日志记录、日志尾部

Block Header,占用12字节

Data部分

Block tailer,占用4字节

Block Header

这个部分是每个Block的头部,主要记录的块的信息

Block Number,表示这是第几个block,占用4字节,是通过LSN计算得来的,占用4字节

Block data len,表示该block中有多少字节已经被使用了,占用2字节

First Rec offet,表示该block中作为第一个新的mtr开始的偏移量,占用2字节

Checkpoint number,表示该log block最后被写入时的检查点的值,占用4字节

人们为数据库设计了一个严谨的体系结构,数据库领域公认的标准结构是三级模式结构,它包括外模式、概念模式、内模式,有效地组织、管理数据,提高了数据库的逻辑独立性和物理独立性。用户级对应外模式,概念级对应概念模式,物理级对应内模式,使不同级别的用户对数据库形成不同的视图。所谓视图,就是指观察、认识和理解数据的范围、角度和方法,是数据库在用户“眼中"的反映,很显然,不同层次(级别)用户所“看到”的数据库是不相同的。

//C++课程设计---学生成绩管理系统

#include <stdioh>

#include <stringh>

#include <iostreamh>

#include <stdlibh>

#include <windowsh>

typedef struct studentinfo //结构体定义

{

int num;//学号

char name[64];//姓名

int sex;//性别,1为男性,0为女性

float math;//数学

float english;//英语

float politic;//政治

float chinese;//语文

float total;//总成绩

struct studentinfo next;

}STUDENT;

#define FILENAME "D:\\1txt"

//定义默认的数据库文件

#define DELAYTIME 1500

//显示信息,延时

void create_menu();

STUDENT new_student();

STUDENT create_linkbyfile(char );

STUDENT del_info(STUDENT );

int save_info(char ,STUDENT ,int);

int find_infile_printf(char );

int pri_whole_link(STUDENT );

STUDENT printf_sort(STUDENT );

void free_link(STUDENT );

void main() //主函数

{

create_menu();

}

STUDENT reverse(STUDENT head)

//功能:链表反转顺序

//参数:head链表头结点指针

{

STUDENT ptemp,p1;

if(head==NULL)

{

return 0;

}

p1=head;//p1使之永远指向排好序的第一个结点,初值为head,head使之永远是已经排好序的最后一个结点

while(head->next!=NULL)//本次循环使ptemp排好序

{

ptemp=head->next;//ptemp指向未排好序的第一个结点

head->next=ptemp->next;//

ptemp->next=p1;//ptemp也排好序了,ptemp变成排好序的第一个结点了

p1=ptemp;//再次让p1成为第一个排好序的结点

}

return p1;//头结点为第一个结点

}

void create_menu()

//功能:输出功能菜单,提供人-机接口

{

char menu_Num;

STUDENT head=NULL;

char ch;

char file_name[256];

while(1)

{

system("cls");

cout<<"\t\t学生成绩管理系统\n";

cout<<"##########################################\n";

cout<<"#\t\t 1新增学生信息\t\t #\n";

cout<<"#\t\t 2加载数据库\t\t #\n";

cout<<"#\t\t 3删除学生信息\t\t #\n";

cout<<"#\t\t 4保存学生信息\t\t #\n";

cout<<"#\t\t 5数据库查询\t\t #\n";

cout<<"#\t\t 6原序输出\t\t #\n";

cout<<"#\t\t 7排序输出\t\t #\n";

cout<<"#\t\t 8退出\t\t\t #\n";

cout<<"##########################################\n";

cout<<"请输入 *** 作编号:";

cin>>menu_Num;

switch (menu_Num)

{

case '1':

free_link(head);//释放链表空间

head=new_student();//新增学生信息

break;

case '2':

free_link(head);//释放链表空间

cout<<"请输入要加载的数据库文件的路径"<<endl;

cin>>file_name;

head=create_linkbyfile(file_name);//读取数据文件

if(head!=NULL)

{

cout<<"数据库"<<file_name<<"已加载"<<endl;

Sleep(DELAYTIME);

}

break;

case '3':

del_info(head);//删除学生信息

break;

case '4'://保存学生信息

if (head==NULL)

{

cout<<"请先生成学生信息"<<endl;

Sleep(DELAYTIME);

}

else

{

cout<<"想将学生信息保存到哪个数据库文件?";

cin>>file_name;

cout<<"请选择保存方式:0追加到文件末尾 1覆盖文件\n";

cin>>menu_Num;

if(save_info(file_name,head,menu_Num-'0')==0)//0表示追加,1表示覆盖

{

cout<<"信息保存失败\n";

}

else

{

cout<<"数据已保存到"<<file_name<<endl;

Sleep(DELAYTIME);

}

}

break;

case '5':

find_infile_printf(FILENAME);//数据库查询

break;

case '6'://原序输出信息

pri_whole_link(head);

cout<<"返回主菜单? Y/N\t";

do

{

cin>>ch;

}while(ch!='Y'&&ch!='y');

break;

case '7'://排序输出信息

do

{

if((head=printf_sort(head))==NULL)

{

cout<<"数据库未加载"<<endl;

Sleep(DELAYTIME);

break;

}

else

{

cout<<"选择其他方式排序? Y/N\t";

cin>>ch;

}

}while(ch=='Y'||ch=='y');

break;

case '8':

free_link(head);//释放链表空间

exit(0);

break;

default:

cout<<"输入有误!请重新输入!"<<endl;

Sleep(DELAYTIME);

break;

}

}

}

STUDENT new_student()

//功能:创建学生信息(通过链表)

//返回值:头结点指针

{

STUDENT pnew,p,head;

float pfloat;

char ch;

head=NULL;

do

{

system("cls");

pnew=(STUDENT )malloc(sizeof(STUDENT)1);

cout<<"请输入学生的学号(0表示取消): ";

cin>>pnew->num;

if(0>=pnew->num)

{

break;

}

cout<<"请输入学生的姓名:";

cin>>pnew->name;

while(1)

{

cout<<"请输入学生的性别:0/1\t";

cin>>pnew->sex;

if(pnew->sex&&pnew->sex-1)

{

cout<<"性别输入错误,0表示女性,1表示男性,请重新输入"<<endl;

}

else

{

break;

}

}

cout<<"请依次输入学生的数学、英语、政治、语文成绩:"<<endl;

for(pnew->total=0,pfloat=&pnew->math;pfloat<&pnew->math+4;)

{

cin>>pfloat;

if(pfloat<0||pfloat>150)

{

cout<<"成绩输入错误,只能为0~150"<<endl;

}

else

{

pnew->total+=pfloat;

pfloat++;

}

}

if(head==NULL)

{

head=pnew;

}

else

{

p->next=pnew;

}

p=pnew;

pnew->next=NULL;

cout<<"##########################该学生信息已生成#########################\n";

cout<<"建立另一个学生的信息? Y/N\t";

cin>>ch;

}while(ch=='Y'||ch=='y');

return head;

}

STUDENT create_linkbyfile(char filename)

//功能:读取文件,创建链表

//参数:如果filename不为空,则打开该文件,如果filename为空,要求输入文件位置

//创建的链表的所有结点的next全部修改,指向物理地址上的下一个结点

{

system("cls");

FILE fp;

STUDENT head,ptemp,pnew;

head=NULL;//初始化head为空

if(filename==NULL)//若filename为空,要求输入文件绝对地址

{

char file_name[256];

cout<<"请输入数据库文件的路径:"<<endl;

cin>>file_name;

if(NULL==(fp=fopen(file_name,"rb")))

{

cout<<"数据库连接失败\n";

return 0;

}

}

else

{

if(NULL==(fp=fopen(filename,"rb")))

{

cout<<"数据库连接失败\n";

return 0;

}

}

for(ptemp=NULL;;)

{

pnew=(STUDENT )malloc(sizeof(STUDENT)1);

if(fread(pnew,sizeof(STUDENT),1,fp)!=NULL)

{

if(ptemp!=NULL)

{

ptemp->next=pnew;

}

else

{

head=pnew;

}

ptemp=pnew;

}

else

{

if(ptemp!=NULL)

{

ptemp->next=NULL;

}

else

{

head=NULL;

}

free(pnew);

break;

}

}

fclose(fp);

return head;

}

STUDENT del_info(STUDENT head)

//根据学号,删除链表的结点

{

system("cls");

STUDENT p1,p2;

int num;

if (head==NULL)

{

cout<<"数据库未加载"<<endl;

Sleep(DELAYTIME);

return 0;

}

cout<<"请输入要删除学生的学号:";

cin>>num;

for(p1=head;p1!=NULL;)

{

if(p1->num==num)//找到

{

if(p1==head)//要删除的结点是头结点

{

head=p1->next;

}

else

{

p2->next=p1->next;

}

cout<<"成功删除!!";

}

p2=p1;

p1=p1->next;

}

return head;

}

int save_info(char filename,STUDENT head,int flag)

//功能:将链表按Binary写入文件末尾

//参数:

//1filename文件名,绝对地址

//2head指向链表的头结点

//3flag 0追加或1覆盖数据

//返回值:失败则返回0

{

system("cls");

FILE fp;

STUDENT p;

char openmethod[8];

if(flag==0)

{

strcpy(openmethod,"ab+");//追加

}

else

{

strcpy(openmethod,"w");//覆盖

}

if(NULL==(fp=fopen(filename,openmethod)))//

{

cout<<"数据库连接失败"<<endl;

Sleep(DELAYTIME);

return 0;

}

else

{

for(p=head;p;p=p->next)

{

if((fwrite(p,sizeof(STUDENT),1,fp))==NULL)

{

cout<<"数据库创建失败"<<endl;

return 0;

}

}

}

fclose(fp);

return 1;

}

int find_infile_printf(char filename)

//功能:根据学号和姓名来查询某个学生

//参数:filename数据库文件

//返回值:失败返回0

//直接搜索文件,缺点是速度慢

//也可先根据文件创建链表,再搜索链表,缺点是如果文件较大,占用内存多

{

system("cls");

FILE fp;

STUDENT stu;

int num;

char stu_name[64];

char ch;

if(filename==NULL)

{

return 0;

}

do

{

memset(stu_name,0,sizeof(stu_name));

cout<<"查询学号或查询姓名? 1查询学号 0查询姓名";

//flag=1根据学号来查询,flag=0根据姓名来查询

cin>>num;

if(num==1)

{

cout<<"输入要查询的学号:";

cin>>num;

cout<<"正在为您查询学号为"<<num<<"的学生……"<<endl;

}

else if(num==0)

{

cout<<"输入要查询的姓名:";

cin>>stu_name;

cout<<"正在为您查询姓名为"<<stu_name<<"的学生……"<<endl;

}

else

{

cout<<"输入有误"<<endl;

return 0;

}

if(NULL==(fp=fopen(filename,"rw")))

{

cout<<"数据库连接失败\n";

return 0;

}

else

{

while(fread(&stu,sizeof(STUDENT),1,fp)!=NULL)

{

if(strcmp(stuname,stu_name)==0||stunum==num)

{

cout<<"学号\t姓名\t性别\t数学\t英语\t政治\t语文\t总成绩\n";

//输出该学生的所有信息

cout<<stunum<<"\t"<<stuname<<"\t"<<stusex<<"\t"<<stumath<<"\t"<<stuenglish<<"\t"<<stupolitic<<"\t"<<stuchinese<<"\t"<<stutotal<<endl;

//不加break;可支持多个相同数据的索引

}

}

}

cout<<"##########################查询完毕#########################\n";

cout<<"查询另一个学生的信息? Y/N\t";

cin>>ch;

}while(ch=='Y'||ch=='y');

fclose(fp);

return 1;

}

int pri_whole_link(STUDENT head)

//功能:显示整条链表的学生信息

//参数:head 头结点指针,如果head为空,返回空

{

system("cls");

STUDENT p;

if (head==NULL)

{

cout<<"数据库未加载"<<endl;

Sleep(DELAYTIME);

return 0;

}

cout<<"学号\t姓名\t性别\t数学\t英语\t政治\t语文\t总成绩\n";

for(p=head;p;p=p->next)

{

cout<<p->num<<"\t"<<p->name<<"\t"<<p->sex<<"\t"<<p->math<<"\t"<<p->english<<"\t"<<p->politic<<"\t"<<p->chinese<<"\t"<<p->total<<endl;

}

return 1;

}

STUDENT printf_sort(STUDENT head)

//功能:根据学号|某科目成绩|总成绩对链表进行排序,然后输出

//参数:head链表头指针,如果head为空,返回空

//返回值:返回新的链表的头结点指针

{

system("cls");

STUDENT p1,p2,ptemp,pfinished=NULL;

char num;

char flag;

if (head==NULL)

{

return 0;

}

cout<<"选择排序依据 0数学成绩1英语成绩2政治成绩3语文成绩4总成绩\n";

while(1)

{

cin>>num;

if(num>'4'||num<'0')

{

cout<<"输入有误,请重新输入 0~4"<<endl;

}

else

{

break;

}

}

cout<<"升序/降序输出? 0降序1升序";

while(1)

{

cin>>flag;

if(flag>'1'||flag<'0')

{

cout<<"输入有误,请重新输入 0~1"<<endl;

}

else

{

break;

}

}

for(p1=head;p1->next!=pfinished;)//对链表进行从大到小排序(这里用冒泡法)

//p1使之总是指向头结点,pfinished使之总是指向已排序好的最前面的结点

//ptemp作为中介,保存p2的上一个结点

{

for(p2=p1;p2->next!=pfinished;)

{

if((&(p2->math)+num-'0')<(&(p2->next->math)+num-'0'))//p2的值小于p2->next的值,交换 ptemp p2 p2->next

{

if(p2==p1)//头结点要交换

{

p1=p2->next;

p2->next=p1->next;

p1->next=p2;

ptemp=p1;

}

else

{

ptemp->next=p2->next;

ptemp=p2->next;

p2->next=ptemp->next;

ptemp->next=p2;

}

}

else//不需要交换,则p2、ptemp前进1位

{

ptemp=p2;

p2=p2->next;

}

}

pfinished=p2;

}

if(flag=='1')

{

p1=reverse(p1);

}

pri_whole_link(p1);

cout<<"##########################信息显示完毕#########################\n";

return p1;

}

void free_link(STUDENT head)

//释放链表空间,如果head,什么都不做

{

STUDENT p1,p2;

for(p1=head;p1;p1=p2)

{

p2=p1->next;//先保存,否则

free(p1);//free后 p1->next数据丢失

}

}

数据结构在计算机中的表示称为数据的物理结构。它包括数据元素的表示和关系的表示。

数据库的物理结构文件按其作用可以分为三类:数据文件、日志文件、控制文件。重做日志文件记录对数据库的所有修改信息。它是三类文件中最复杂的一类文件,也是保证数据库安全与数据库备份与恢复有直接关系的文件。

以上就是关于大型数据库设计原则全部的内容,包括:大型数据库设计原则、数据库系统模式有哪三种、数据库系统的三级模式分别为什么模式等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

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

原文地址:https://54852.com/sjk/9453911.html

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

发表评论

登录后才能评论

评论列表(0条)

    保存