⼀、C++语⾔基础
1、extern关键字作⽤
第⼀:当⼀个函数或者变量在⼀个⽂件中声明时使⽤extern关键字修饰,则该函数或者变量可以在其他⽂件中调⽤,但是要include使⽤extern声明函数或者变量的⽂件。⽐如在头⽂件中声明⼀个extern修饰的变量,在源⽂件中定义它。第⼆:当使⽤extern \"C\"时,是告诉编译器在编译这段代码块时按照C的规则去识别。2、static关键字作⽤
第⼀:static修饰局部变量时,使被修饰变量成为静态变量,存储在静态区。该变量在main函数前初始化,在程序退出时销毁。局部静态变量使得变量在函数退出后不会被销毁,因此可以使得再次调⽤该函数时,保证数据不变。
第⼆:static修饰全局变量,因为全局变量存储在全局区,⽽全局区和静态区属于同⼀区域,所以存储位置不发⽣改变,但是被static修饰的全局变量只能被该包含该定义的⽂件访问。
第三:static修饰函数,则使得函数只能在包含该函数定义的⽂件中被调⽤。如果将static函数定义在头⽂件中,则每个包含该头⽂件的⽂件都实现了这个函数,因此static实现了不同⽂件中定义同名函数这⼀⽬的,⽽不发⽣冲突。在多⼈协同的项⽬中,为了避免出现同名函数冲突,可以把函数定义为static,这样可以避免同名冲突。
第四:static修饰类中的成员变量和成员函数,可以使不同对象之间实现数据共享。3、volatile关键字作⽤
⾸先说⼀下volatile的三个特性:易变性、不可优化性、顺序性。
因为CPU对寄存器的访问速度⽐对内存的访问速度要快得多,所以CPU会优先访问在寄存器中存储的结果或者备份,但是此时内存中的东西可能发⽣了改变,⽽寄存器中的内容还是之前遗留下来的,当出现我们希望CPU优先访问内存时(内存管理)⽽不是⾃⼰去访问寄存器,就可以使⽤volatile关键字,指明希望CPU读取数据的位置。
⼀个参数可以同时使⽤const和volatile修饰吗?答案是可以的,⽐如只读状态寄存器。4、const关键字作⽤
第⼀:const修饰基本数据类型,修饰基本数据类型或者数组,则说明该数据已经被定义为常量型,不可以改变数据的值。
第⼆:const修饰指针或引⽤变量,const位于*左边,则标识const修饰指针所指向内存的变量类型,即指针指向⼀个常量,指针可以指向不同的地⽅,但是指针所指向的内存中数据不可以改变;const位于*右边,标识const修饰指针,即指针本⾝是个常量,表⽰指针不可指向其他内存地址,⽽指针指向的内存中的内容可以改变。const修饰引⽤变量⼀般在类的拷贝构造函数的参数中和重载函数返回值和参数中使⽤。
第三:const在函数中的使⽤,const修饰形参说明对形参常量化,参数成为只读参数。const修饰函数返回值,也是起到相应的保护作⽤。第四:const在类中的使⽤,不能在类声明中初始化const成员变量,只能在构造函数的初始化表中对其初始化。const修饰类对象说明对象为常量对象,只能调⽤常量⽅法,其他类⽅法不可调⽤。5、new和malloc
第⼀:new分配内存按照数据类型分配,malloc分配内存按照⼤⼩分配,但都是在堆区上分配存储空间。
第⼆:new是C++关键字,malloc是⼀个C函数,new在分配内存时会调⽤构造函数,⽽malloc底层是使⽤操作系统的系统调⽤实现的。第三:new返回的是指定对象的指针,malloc返回的是void*类型,因此使⽤malloc多需要进⾏类型转换。第四:new分配内存使⽤delete销毁,malloc对应free,new[]对应delete[],使⽤delete时会调⽤对象的析构函数。
第五:malloc分配内存不⾜时可以⽤realloc扩容,new没有扩容操作。new分配内存失败时会抛出异常,malloc分配失败时返回NULL。第六:malloc申请内存后不可赋初值,⽽new可以。6、C++特性封装、继承、多态
7、讲讲C++多态和虚函数、纯虚函数
第⼀:C++多态分为静态多态和动态多态,静态多态通过模板和重载技术实现,在编译时确定。动态多态通过虚函数和继承关系实现,在运⾏时动态确定。动态多态实现有两个条件,⼀是虚函数,⼆是基类指针或引⽤指向派⽣类的对象。
第⼆:虚函数是指在类中⽤virtual关键字修饰的成员函数,它提供⼀种接⼝界⾯,允许在派⽣类中重定义。在声明虚函数的同时,C++内部
会维护⼀个虚函数表,虚函数表的地址在每个对象的⾸地址,对象调⽤虚函数是查找该表中的函数指针来获取函数的地址。每个对象中保存的不是⼀个完整的虚函数表,⽽是⼀个指向该表的指针,同类的不同对象保存相同的表指针。
第三:纯虚函数的作⽤是只在基类中声明⼀个接⼝⽽不去实现它,这些接⼝应该被派⽣类所实现,当⼀个类中⾄少有⼀个纯虚函数时,该类被称为抽象类。抽象类中也可以包含虚函数,⽽抽象类只能作为基类,不可⽤于创建对象。⼦类从基类中继承来的纯虚函数,在⼦类中仍然是虚函数。
8、为什么对于存在虚函数的类中析构函数要定义为虚函数
因为如果析构函数没有定义为虚函数,则在销毁对象的时候只会调⽤⼦类的析构函数,只能销毁⼦类中定义的数据,⽽不会向下实现多态。析构函数的调⽤次序是先调⽤派⽣类的析构函数再调⽤基类的析构函数,于调⽤构造函数顺序相反。9、析构函数是否可以抛出异常
不能。C++标准明确规定析构函数不可抛出异常,因为当对象操作有异常抛出时说明对象在抛出异常的同时已经失效,这样对象就超出了它的作⽤域,此时对象会调⽤析构函数释放空间,如果析构函数可以抛出异常,则在上⼀个异常没有处理完的情况下,⼜在析构函数中抛出了另⼀个异常,会导致程序崩溃。10、指针和引⽤的区别
第⼀:指针保存的时对象的地址,引⽤是对象的别名,指针作为变量会对其分配空间,⽽引⽤不会。第⼆:指针使⽤时可以改变它所指向区域,⽽引⽤在初始化以后不可再改变。第三:指针可以⽤NULL初始化,⽽引⽤只能使⽤实体对象初始化。第四:指针有常量指针(可⽤const修饰),引⽤没有常量引⽤。第五:指针⾃增操作是改变所指地址,引⽤⾃增改变所代表的变量数据。11、指针与数组的区别
第⼀:修改指针所指存储区域的内容和修改数组中的内容的⽅式不同,当指针指向常量区数据时不可使⽤下标访问,只有当指针指向数组⾸地址时可⽤使⽤。
第⼆:使⽤sizeof计算指针⼤⼩和数组⼤⼩的结果不相同,计算指针时返回指针本⾝的⼤⼩,⽐如int*为4,⽽计算数组时返回整个数组的⼤⼩,⽐如char a[10]返回10。
第三:数组名做参数时会退化为指针(sizeof除外)。12、什么是智能指针
智能指针本⾝是个类,程序员在为指针进⾏内存分配后,可能忘记使⽤delete销毁内存,为了避免这个问题,出现了智能指针。智能指针在创建时调⽤构造函数,在消亡时(超出使⽤范围以后)⾃动调⽤析构函数,这样就起到⼀个内存回收的作⽤。
第⼀:auto_ptr(C++98⽅案,C++11已经弃⽤),该指针采⽤所有权模式,假设有auto_ptr p1和p2,此时p1已经初始化,将p1赋值给p2,则p2剥夺了p1的所有权,当程序运⾏时访问p1会报错,因为此时p1所指位置并不确定,因此存在潜在内存问题。
第⼆:unique_ptr(替代auto_ptr),unique_ptr实现独占式拥有或严格拥有概念,保证同⼀时间内只有⼀个只能指针可以指向该对象,同时智能指针本⾝是⼀个类,在对象⽣命周期结束以后会⾃动调⽤析构函数释放内存,从⽽避免了内存泄漏问题。那么刚才说的有关auto_ptr出现的情况如果⽤unique_ptr替换则⽆法通过编译。
第三:shared_ptr实现共享式拥有,多个智能指针可以指向⼀个相同对象,该对象和其相关资源会在最后⼀个引⽤被销毁时释放。shared_ptr是为了解决auto_ptr在对象所有权上的局限性,在使⽤引⽤计数的机制上提供了可以共享所有权的智能指针。
第四:weak_ptr是⼀中不控制对象⽣命周期的智能指针,它指向⼀个shared_ptr管理的对象,其设计的⽬的是为了配合shared_ptr的使⽤,它只能从⼀个shared_ptr或另⼀个weak_ptr对象构造,其构造和析构不会引起引⽤计数的增加或减少。weak_ptr是⽤来解决shared_ptr相互引⽤时的死锁问题(如果两个shared_ptr相互引⽤,那么这两个指针的引⽤计数永远不可能降到0,资源永远不能释放)。13、什么是深拷贝和浅拷贝
浅拷贝是指对对象指针的拷贝,拷贝后,两个指针指向同⼀个内存。深拷贝不但对指针进⾏拷贝,还对指针所指向的内容进⾏拷贝,拷贝后的指针指向的内存地址和之前的指针指向的内存地址不同,但两个地址中的内容相同。14、C++的四种类型转换
第⼀:const_cast⽤于将const转换成⾮const。
第⼆:static_cast⽤于各种隐式转换,⽐如⾮const转const,void*转指针等。
第三:dynamic_cast⽤于动态类型转换,只能⽤于含有虚函数的类,只能转指针或引⽤。第四:reinterpre_cast万能转换,⽐如int转指针。但容易出现问题,⼀般很少使⽤。
为什么C中有强转这个操作,还要诞⽣C++中的类型转换呢?因为C的转换不够明确,不能进⾏错误检查,容易出现错误。
15、内存对齐的原则是什么第⼀:从0位置开始存储;
第⼆:变量存储的起始位置是该变量⼤⼩的整数倍;
第三:结构体总⼤⼩是结构体中最⼤元素的整数倍,长度较⼩的元素需要补齐内存空间;(嵌套结构也是如此)16、内联函数与宏定义的区别
第⼀:宏定义是在预编译时候进⾏替换,内联函数在编译阶段对调⽤内联函数的地⽅进⾏替换,减少了调⽤过程,但是使得编译⽂件变⼤,因⽽内联函数适合函数体简单的函数。
第⼆:内联函数⽐宏替换更加安全,使代码更易于调试。因为宏定义是简单的⽂本替换,不会被编译器所认识,⽽内联函数要通过编译就要受到编译器的检测。
第三:宏定义函数要注意给所有单元加上括号,不然在复杂语句中做替换容易发⽣危险。17、C++内存区域分为哪⼏块
第⼀:栈区,⽤于存储函数的参数,局部变量的值等,由编译器⾃动分配和释放。第⼆:堆区,程序员分配和释放,分配⽅式类似链表,在内存中属于不连续存储。
第三:全局和静态区,存储全局变量和静态变量,其中已初始化和未初始化的变量会分开存储,存储区域由系统⾃由管理。第四:⽂字常量区,存储常量字符,程序结束后释放。第五:程序代码区,存放函数体的⼆进制代码。18、重载(overload)和重写(override)的区别
重载:指允许多个函数同名,⽽这些函数的参数表不同(类型或个数都可)。重载时,编译器根据函数不同的参数表判断调⽤哪个⽅法,是静态的。⽅法调⽤和函数地址在编译期已经绑定好了。
重写:指⼦类重新定义⽗类虚函数的⽅法。⼦类重新定义⽗类的虚函数后,⽗类指针根据赋给它的不同⼦类指针,动态的调⽤属于⼦类的此类函数,这样函数的地址在编译期⽆法确定,是动态的。19、动态链接和静态链接的区别
动态链接是只建⽴⼀个引⽤的接⼝,⽽真正的代码和数据存放在另外⼀个可执⾏模块中,在运⾏时再装⼊;⽽动态链接是把所有的代码和数据都复制到本模块中,运⾏时就不再需要库了。
⼆、STL
1、STL的六⼤组件是什么
第⼀:容器,各种数据,如序列式容器和关联式容器。第⼆:算法,各种常⽤算法,如sort、search、erase等。
第三:迭代器,容器和算法之间的胶合剂,⼀种泛型指针,每个容器有⾃⼰的迭代器,但都继承⾃源⽣迭代器。第四:仿函数,类似函数,是⼀种算法策略。
第五:配接器,⼀种⽤来修饰容器、仿函数、迭代器接⼝的东西。例如queue和stack虽然看似容器但其底层操作都借助于deque,所以queue和stack也可看成配接器。
第六:配置器,负责空间配置和管理,是动态的。
交互关系:容器通过配置器取得存储空间,算法通过迭代器存取容器内容,仿函数协助算法完成不同的策略变化,配接器修饰或套接仿函数利⽤底层接⼝。
2、STL容器中vector和map的实现原理
第⼀:vector属于顺序容器,它是⼀个动态数组,⽀持插⼊、删除、查找等操作。vector在内存中是⼀块连续的存储空间,在旧内存空间不够的情况下,vector会⾃动分配⼀个⽐原空间⼤两倍的新空间,将原数据拷贝到新空间,然后释放原空间。由于vector空间的重新分配,导致旧vector的迭代器全部失效需要重新配置。vector中数据的读操作效率极⾼,⽽插⼊操作⼀般只使⽤尾插,使⽤随机插⼊insert时需要移动插⼊位置以后的所有元素,效率就⽐较低了。
第⼆:map属于关联容器,以键值对的⽅式存储数据,⽽关键字便起到了索引的作⽤,⼀般关联容器的底层使⽤红⿊树结构实现,插⼊和删除操作都在O(logN)的时间复杂度。当然有其他结构⽐如mulitmap使⽤哈希思想实现,查找效率极⾼,⼀般在常数级,但是前期哈希表的建⽴耗时较多。
3、部分关联容器的底层是红⿊树,那么红⿊树的特点是什么
第⼀:红⿊树是⼀种平衡⼆叉查找树,与AVL树的区别是AVL树是完全平衡,红⿊树是基本平衡。
第⼆:选⽤红⿊树的原因是其插⼊删除的效率都是O(logN),⽽在其结构上,红⿊树想⽐AVL树插⼊和删除时旋转的次数相差较⼤,红⿊树⾄多旋转三次,⽽AVL树为了保证完全平衡需要旋转多次。
第三:红⿊树的定义,(1)节点是红⾊或者⿊⾊;(2)⽗节点是红⾊则⼦节点不可为红⾊;(3)根是⿊⾊的那么NULL节点被认为是⿊⾊的;(4)从根节点到每个叶⼦节点路径上的⿊⾊节点数量相同。4、为何每次insert之后,以前保存的迭代器不会失效
迭代器这⾥就相当于指向节点的指针,内存没有改变,指向内存的指针也就不会失效。⽽相对于vector来说,每次删除和插⼊指针都有可能失效,调⽤push_back在尾部插⼊也是如此,因为为了保证内存数据的连续存放,vector迭代器指向的那块内存在删除和插⼊过程中可能已经被其他内存覆盖或者内存已经释放,在插⼊操作中可能出现分配的空间不⾜情况,则同上⾯所说vector内部会⾃动重新分配空间,此时之前旧空间上建⽴的迭代器就会失效。特别是在和find等算法在⼀起使⽤时,应该牢记不要使⽤失效的iterator。5、hash_map和map的区别有哪些
第⼀:构造函数不同,hash_map需要哈希函数、等于函数;⽽map只需要使⽤⽐较函数。第⼆:存储结构不同,hash_map采⽤哈希表存储,map⼀般采⽤红⿊树实现。6、请讲⼀下STL中各个容器在使⽤erase⽅法后迭代器的状态
第⼀,对于序列容器vector,deque来说,使⽤erase(itertor)后,后边的每个元素的迭代器都会失效,但是后边每个元素都会往前移动⼀个位置,但是erase会返回下⼀个有效的迭代器;
第⼆,对于关联容器map,set来说,使⽤了erase(iterator)后,当前元素的迭代器失效,但是其结构是红⿊树,删除当前元素的,不会影响到下⼀个元素的迭代器,所以在调⽤erase之前,记录下⼀个元素的迭代器即可。
第三,对于list来说,它使⽤了不连续分配的内存,并且它的erase⽅法也会返回下⼀个有效的iterator,因此上⾯两种正确的⽅法都可以使⽤。
三、⽹络原理(TCP/IP和http协议)
1、TCP和UDP的区别
第⼀:TCP基于有连接,UDP基于⽆连接。有链接就是tcp在传输前先发送连连接请求和应答包,确定客户端与服务器双⽅已经连接上了再开始传输数据,⽽⽆连接的udp在发送数据前并不考虑对⽅能否接收到,甚⾄⽬的地址⽆效也能单⽅传输。
第⼆:TCP保证可靠传输,UDP属于不可靠传输。tcp能够确保数据⼀定可送到⽬的地址,因为当tcp连接没有建⽴的时候不会传输数据,为了实现可靠传输,tcp有超时重传、应答等机制,⽽udp不可以保证数据⼀定送达。
第三:TCP基于流模式,UDP基于数据报模式。tcp把数据看成⽆结构字符流,⽆边界,通过客户端和服务器通过建⽴缓冲区来存储数据,⽽udp的每个数据报属于⼀个独⽴对象,有⼤⼩限制。
第四:TCP连接只能点对点,UDP则可以⼀对⼀、⼀对多或多对多。这样⼀来⼴播和多播便只能使⽤udp。第五:TCP结构复杂,建⽴过程较慢,UDP结构简单,建⽴过程较快。
第六:TCP有确认、重传、拥塞控制机制,在没有建⽴连接时不会传输数据,所以不会导致通信流量的浪费,⽽UDP在没有建⽴连接或者对⽅已经退出的情况下依然会继续发送数据,导致通信流量的浪费。2、什么是TCP连接的三次握⼿和四次挥⼿
3、什么是套接字(Socket)
套接字本质上是个⼆元组,由IP地址和端⼝号组成。互联⽹通信⾄少需要⼀对套接字,分别为Client Socket和Server Socket,两类套接字内部存储⽬的IP地址和⽬的端⼝号及源IP地址和源端⼝号。套接字之间的连接过程分为三部:服务器监听、客户端请求、连接确定。4、http协议的特点有哪些
第⼀:⽆连接,http限制每次连接只处理⼀个请求,服务器处理完客户端的请求,收到客户应答后⽴即断开,这样可以节省传输时间。第⼆:⽆状态,指协议对于事务处理没有记忆功能,服务器根据请求发送完数据后不会记录信息,这就衍⽣出cookie机制解决⽆状态问题。第三:媒体独⽴,当客户端向服务器发送请求时,只需要简单的填写请求路径和⽅法即可,请求的发送通过浏览器或某些程序中的发送语句发送,并允许传输任意类型和格式的数据对象。5、讲⼀讲get/post的区别
第⼀:get重点是从服务器上获取资源,post是向服务器发送资源。
第⼆:get传输数据时通过url请求,该过程⽤户可见;post传输数据通过http的post机制,将字段与对应值封存在请求实体中发送,该过程⽤户不可见。
第三:get传输数据量⼩,收到url的长度限制,但效率⾼;post可以传输⼤量数据,所以上传⽂件只能⽤post⽅法。第四:get不安全,因为url可见,post较get安全性较⾼。6、https与http的区别
第⼀:https是在http与传输层之间奖赏了⼀个ssl。第⼆:https使⽤对称加密与⾮对称加密。7、http的结构是什么样的
http数据由请求⾏,⾸部字段,空⾏,报⽂主体四个部分组成。⾸部字段⼜分为:通⽤⾸部字段、请求⾸部字段、响应⾸部字段、实体⾸部字段。
8、浏览器中输⼊⼀个url之后发送了什么,需要⽤到哪些协议
浏览器中输⼊URL,⾸先浏览器要将URL解析为IP地址,解析域名就要⽤到DNS协议,⾸先主机会查询DNS的缓存,如果没有就给本地DNS发送查询请求。DNS查询分为两种⽅式,⼀种是递归查询,⼀种是迭代查询。如果是迭代查询,本地的DNS服务器,向根域名服务器发送查询请求,根域名服务器告知该域名的⼀级域名服务器,然后本地服务器给该⼀级域名服务器发送查询请求,然后依次类推直到查询到该域名的IP地址。DNS服务器是基于UDP的,因此会⽤到UDP协议。得到IP地址后,浏览器就要与服务器建⽴⼀个http连接。因此要⽤到http协议,http协议报⽂格式上⾯已经提到。http⽣成⼀个get请求报⽂,将该报⽂传给TCP层处理。如果采⽤https还会先对http数据进⾏加密。TCP层如果有需要先将HTTP数据包分⽚,分⽚依据路径MTU和MSS。TCP的数据包然后会发送给IP层,⽤到IP协议。IP层通过路由选路,⼀跳⼀跳发送到⽬的地址。当然在⼀个⽹段内的寻址是通过以太⽹协议实现(也可以是其他物理层协议,⽐如PPP,SLIP),以太⽹协议需要直到⽬的IP地址的物理地址,有需要ARP协议。
四、操作系统
1、进程和线程的区别及联系
第⼀:定义。进程是操作系统进⾏资源分配的⼀个独⽴单位,是具有⼀定独⽴功能的程序在某个数据集合上的⼀次执⾏过程。线程是进程内部的⼀个实体,是CPU调度的基本单位。
第⼆:关系。⼀个进程可以创建或撤销多个线程,同⼀进程中的所有线程共享该进程的数据,同⼀进程中的⼀个线程崩溃,则该进程中的所有线程崩溃,⼀般使⽤⼀个进程中创建多个线程来模拟进程通信。
第三:区别。进程由操作系统管理,线程由cpu管理;进程具有独⽴地址空间,⼀个进程崩溃后在操作系统的保护模式下不会对其他进程产⽣影响,⽽线程共享该线程所在进程的地址空间,⼀个线程崩溃则所有线程崩溃。因此多进程⽐多线程健壮,但多线程⽐多进程效率⾼;对于程序要求同时执⾏并且⼜需要共享数据的并发操作只使⽤多线程,不适⽤多进程。2、讲⼀下线程回收
线程回收需要⽤到pthread_join(),该函数⽤于等待其他线程结束,当调⽤pthread_join时,当前线程会处于阻塞状态,直到被调⽤的线程结束,当前线程才会重新开始。如果⼀个线程是⾮分离的(默认情况下创建的线程都是⾮分离的)并且没有对该线程使⽤pthread_join,则该线程结束后并不会释放其内存空间,这会导致该线程变成“僵⼫线程”。3、线程同步的⽅式有哪些
使⽤互斥量、条件变量和信号量进⾏线程控制。4、谈⼀下死锁
死锁是指多个进程或者线程为了争夺某种资源⽽⼜互相等待其他进程或线程释放它的状态的现象。死锁产⽣的必要条件有互斥条件、请求和保持条件、不剥夺条件、环路等待条件。预防死锁可以使⽤资源⼀次性分配、可剥夺资源、资源有序分配三种⽅法;然⽽预防死锁的⼏种策略会严重损害系统性能,因此再避免死锁时,要施加较弱的限制,从⽽获得较满意的系统性能。解除死锁的⽅法有两个:进程终⽌(终⽌所有死锁进程和⼀次只终⽌⼀个进程直⾄死锁消失)和资源抢占(从⼀个或多个死锁进程⾥抢占⼀个或多个资源)。5、进程调度的⽅法有哪些第⼀:先来先服务
第⼆:短作业优先调度(平均等待时间最短)第三:优先级调度第四:时间⽚轮询调度第五:多级队列第六:多级反馈队列
6、什么是虚拟内存,虚拟内存的优点
第⼀:虚拟内存允许执⾏进程不必完全再内存中,每个进程拥有独⽴的地址空间,这个进程空间被分为⼤⼩相等的多个块,称为页。每个页都是⼀段连续的地址,这些页被映射到物理内存。当程序引⽤到⼀部分在物理内存中的地址空间时,由硬件⽴即进⾏必要的映射;当程序引⽤到⼀部分不在物理内存中的地址空间时,由操作系统负责将缺失的部分装⼊物理内存并重新执⾏失败命令。
第⼆:使⽤虚拟内存的优点有,在内存中可以保留多个进程,系统的并发度得到提⾼;解除了⽤户与内存之间的紧密约束,进程可以⽐内存的全部空间还⼤。7、讲⼀下epoll
五、数据库
1、什么是聚集索引,什么是⾮聚集索引
第⼀:聚集索引是该索引中键值的逻辑顺序决定了表中相应⾏的物理顺序。
第⼆:⾮聚集索引是数据存储和索引存储分开,索引带有指针指向数据的存储位置。
第三:两者区别。聚集索引⼀个表只能有⼀个,⽽⾮聚集索引⼀个表可以存在多个;聚集索引存储记录是物理上的连续存在,⽽⾮聚集索引是逻辑上的连续。
2、现在普遍关系数据库⽤的数据结构是什么答:B树或者B+树3、索引的优点和缺点
第⼀:建⽴索引的优点。⼤⼤加快数据的检索速度;创建唯⼀性索引,保证数据库表中每⼀⾏数据的唯⼀性;加速表和表之间的连接;在使⽤分组和排序⼦句进⾏数据检索时,可以显著减少查询中分组和排序的时间。
第⼆:索引的缺点。索引需要占物理空间;当对表中的数据进⾏增加、删除和修改的时候,索引也要动态的维护,降低了数据的维护速度。4、关系数据库和⾮关系数据库
简单来说,关系模型指的就是⼆维表格模型,⽽⼀个关系型数据库就是由⼆维表及其之间的联系所组成的⼀个数据组织。⾮关系型数据库提出另⼀种理念,例如,以键值对存储,且结构不固定,每⼀个元组可以有不⼀样的字段,每个元组可以根据需要增加⼀些⾃⼰的键值对,这样就不会局限于固定的结构,可以减少⼀些时间和空间的开销。5、什么是悲观锁与乐观锁
第⼀:悲观锁是假定会发送并发冲突,屏蔽⼀切可能违反数据完整性的操作。第⼆:乐观锁假定不会发⽣并发冲突,只在提交操作时检查是否违反数据完整性。
因篇幅问题不能全部显示,请点此查看更多更全内容