C#就业形势
C# 的市场份额在慢慢提升,有以下几个原因:
- 微软亲儿子,跟随壮大
- .NET 平台的普及
- 开源社区的壮大
- 企业级应用的需求
- .Net 跨平台特性
另外C#在国有企业及上位机开发上普及度高(贴近日常用户体验),在Unity开发,微软在AI方面大布局与优势,C#在AI领域的热度也会不断上升。
C#面试准备工作
- 准备精简且与公司招聘相符的简历(突出招聘要求的技能点,可针对不同公司写针对性简历及准备多份简历)
- 熟练自我介绍(简短介绍自己毕业院校,专业方向,工作经历,兴趣爱好。重点介绍所用技能及成就)
- 掌握c#知识技能点
- 清楚且熟练描述所做项目及所用技能
- 发表自己对程序理解及良好编程习惯
C#面试基础知识及技能点
基础知识和语法
程序:数据和算法的结合
面向对象的三大特性:封装,继承,多态
堆栈(stack):在RAM区域,编译器自动分配释放,通过操作堆栈指针可以直接操作这部分内存,创建程序时编译器需要知道从栈里分配多少存储空间
堆(heap):也在RAM中,由程序员分配释放,区别于栈就是堆不需要知道创建对象时需要从堆里分配多大的存储空间,也不知道存储多长时间
值类型的实例分配在栈上,引用类型分配在托管堆上。
装箱:把值类型转换为 object 类型或由此值类型实现的任何接口类型
拆箱:把引用类型转换为值类型
装箱比拆箱更消耗内存和CPU处理时间,尽量避免拆装箱。
类:对一群具有相似特征和行为事物(对象)的抽象,方便人区分和管理,类属于引用类型,可以继承。
结构体:是值类型数据结构(不可继承),它使得一个单一变量可以存储各种数据类型的相关数据。struct 关键字用于创建结构体。
结构存储在栈中。堆空间大,但访问速度较慢,栈空间小,访问速度相对更快。故而,当我们描述一个轻量级对象的时候,结构可提高效率,成本更低。
字段(Fields):字段是类中的变量,用于存储对象的状态和数据。
属性(Properties):属性提供了一种通过方法访问和修改字段的方式。属性定义了读取和写入字段值的访问器方法,以便对字段进行封装和控制访问,数据更安全。
枚举:枚举是一组命名整型常量。枚举类型是使用 enum 关键字声明的。
构造函数(Constructor):构造函数是一种特殊的方法,用于创建类的对象并初始化其状态。构造函数具有与类名称相同的名称,不返回任何值,可以接受参数以便在创建对象时提供初始值。
析构函数:同样是类中的一个特殊成员函数,主要用于在垃圾回收器回收类实例时执行一些必要的清理操作。
Runtime(运行时):提供两个机制,一个机制能通知发生了紧急事件;另一个机制则规定在发生事件时应该允许什么方法,这正是事件和委托的用途。
委托:委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。
事件:对象的某个状态发生了变化所引起的行为。
抽象类:抽象类是能够包含抽象成员的类。抽象类只能作为基类使用(单继承),不能被实例化(为子类提供模板,但不具体实现)。抽象类可以包含普通方法及其实现。
接口:接口是从抽象类演变而来的,如果抽象类中的所有方法都是抽象方法,这个抽象类就可以叫做接口(要求子类实现所有接口方法且方法为共有,可多继承,可以包含属性,索引器,不能用成员变量,不能定义字段,不能包含方法实现)。
抽象方法:只包含方法定义,但没有具体实现的方法,需要其子类或者子类的子类来具体实现。
虚方法:虚方法就是可以被子类重写的方法,如果子类重写了虚方法,那么运行时将使用重写后的逻辑,如果没有重写,则使用父类中虚方法的逻辑.(选择性重写,如报表)
泛型:在方法实现前未指明的类型,允许您延迟编写类或方法中的编程元素的数据类型的规范,直到实际在程序中使用它的时候。
lambda表达式:是能返回一个方法的表达式,由参数列表和方法体组成。
匿名方法:委托提供一种机制,可以为委托定义匿名方法,匿名方法没有名称,只有方法体,编译器会定指定一个名称。
特性(Attribute):用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息。
反射(Reflection):反射指程序可以访问、检测和修改它本身状态或行为的一种能力。程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。
索引器(Indexer):允许一个对象可以像数组一样使用下标的方式来访问,像一个 虚拟数组(virtual array)。
进程(Process):是Windows系统中的一个基本概念,它包含着一个运行程序所需要的资源。一个正在运行的应用程序在操作系统中被视为一个进程,进程可以包括一个或多个线程。线程是操作系统分配处理器时间的基本单元,在进程中可以有多个线程同时执行代码。进程之间是相对独立的,一个进程无法访问另一个进程的数据(除非利用分布式计算方式),一个进程运行的失败也不会影响其他进程的运行,Windows系统就是利用进程把工作划分为多个独立的区域的。进程可以理解为一个程序的基本边界。是应用程序的一个运行例程,是应用程序的一次动态执行过程。
线程(Thread):是进程中的基本执行单元,是操作系统分配CPU时间的基本单位,一个进程可以包含若干个线程,在进程入口执行的第一个线程被视为这个进程的主线程。在.NET应用程序中,都是以Main()方法作为入口的,当调用此方法时系统就会自动创建一个主线程。线程主要是由CPU寄存器、调用栈和线程本地存储器(Thread Local Storage,TLS)组成的。CPU寄存器主要记录当前所执行线程的状态,调用栈主要用于维护线程所调用到的内存与数据,TLS主要用于存放线程的状态信息。
同步与异步:
同步是顺序执行,执行完一个再执行下一个,需要等待和协调运行。异步是彼此独立运行,在等待某事件的过程中继续做其他事情。
并发与并行:
并发:一个处理器同时处理多个任务。
并行:多个处理器或者多核处理器同时处理多个不同任务。
多线程:
优点:1.资源分配更合理,并行处理程序。2.随时可以停止 。3.可设置优先级。
缺点:1.在耗时或占用大量资源时容易引发阻塞,使界面卡死。2.增加了CPU额外开销。3.产生竞争关系,导致线程死锁。多线程处理:
1.主线程等待一个或多个子线程执行完后再执行(或者)等待多个子线程中任何一个任务完成再执行
task1.Wait():等待task1线程完成再执行后面操作
Task.WaitAll(task1,task2):等待task1,task2线程完成再执行后面操作
Task.WaitAny(task1,task2):等待task1或者task2完成再执行后面操作
2.某个子线程等待一个或多个子线程执行完后再执行(或者)等待多个子线程中任何一个任务完成再执行
Task.WhenAll(task1,task2)
Task.WhenAny(task1,task2)
3.线程嵌套(父子关系):在复杂的多线程编程中,需要更清晰的表现出线程之间的关系时使用。
TaskCreationOptions.AttachedToParent(附加到父级线程),parentTask.Start();parentTask.Wait();
4.开启长耗时任务的线程
TaskCreationOptions.LongRunning
5.线程取消
CancellationTokenSource cts=new CancellationTokenSource();cts.Token,cts.Cancel();
6.线程取消并自动清理
cts.Token.Register(()=>{//业务});
7.线程延时自动取消,不需要手动取消
CancellationTokenSource cts=new CancellationTokenSource(2000);
8.暂停线程
ManualResetEvent resetEvent = new ManualResetEvent(true);
resetEvent.Reset();
9.继续线程
resetEvent.Set();
static void Main(string[] args)
{
CancellationTokenSource source = new CancellationTokenSource();
//注册任务取消的事件
source.Token.Register(() =>
{
Console.WriteLine("任务被取消后执行xx操作!");
});
int index = 0;
//开启一个task执行任务
Task task1 = new Task(() =>
{
while (!source.IsCancellationRequested)
{
Thread.Sleep(1000);
Console.WriteLine($"第{++index}次执行,线程运行中...");
}
});
task1.Start();
//延时取消,效果等同于Thread.Sleep(5000);source.Cancel();
source.CancelAfter(5000);
Console.ReadKey();
}
异常处理:
单线程发生异常,如果需要捕捉,只是try-catch;但是多线程内部发生异常之后,在子线程内部try-catch是无法捕捉到的。但是异常会在Wait中抛出
try{tasl.wait()}catch(AggregateException ex){//异常处理}
参考:https://blog.csdn.net/qq_33101689/article/details/106228965
线程池:使那些休眠或等待的线程暂时挂起,以减少占用资源,等需要用时重新启动,减少了大量创建和销毁线程的开销.
设置线程池最大最小:ThreadPool.SetMaxThreads(int workerThreads,int CompletionPortThreads);
添加任务到线程池:ThreadPool.QueueUserWorkItem(new WaitCallBack(方法名),?参数);
Control.Invoke:在拥有此控件的基础窗口句柄的线程上同步执行指定委托;Control.BeginInvoke:在拥有此控件的基础窗口句柄的线程上异步执行指定委托;
多线程缺点:1.等候使用共享资源时造成程序的运行速度变慢。这些共享资源主要是独占性的资源 ,如打印机等。 2.对线程进行管理要求额外的 CPU开销。 3.线程的死锁。即较长时间的等待或资源竞争以及死锁等多线程症状。
线程详细参考:C#及WPF多线程定义和使用1(Thread)_wpf thread-CSDN博客
数据结构:数据结构(Data Structure) 是在相互之间存在的一种或多种特定关系的数据元素集合.
常用数据结构:1.数组Array 2.数组列表ArrayList 3.列表List 4.哈希表 Hashtable<K,T> 5. 字典Dictionary<K,T> 6.链表LinkedList 7.队列Queue<T> 8. 栈Stack<T>
设计原则
1. 单一职责原则(Single Responsibility Principle)
每一个类应该专注于做一件事情。一个类改变,不会影响其他类,便于维护。
2. 开闭原则(Open Close Principle)
面向扩展开放,面向修改关闭。源代码不改变,只是实现它的扩展,减少代码审查和测试。
3. 里氏替换原则(Liskov Substitution Principle)
类可以扩展父类的功能,但不能改变父类原有的功能。
4. 依赖倒置原则(Dependence Inversion Principle)
实现尽量依赖抽象,不依赖具体实现。
5. 接口隔离原则(Interface Segregation Principle)
应当为客户端提供尽可能小的单独的接口,而不是提供大的总的接口。
6. 迪米特法则(Law Of Demeter)
又叫最少知识原则,一个软件实体应当尽可能少的与其他实体发生相互作用。
7. 组合/聚合复用原则(Composite/Aggregate Reuse Principle CARP)
尽量使用合成/聚合达到复用,尽量少用继承。原则: 一个类中有另一个类的对象。
设计模式
单例模式:一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,避免频繁创建对象,节约内存。(饥饿、懒汉模式)
工厂模式:现了对责任的分割,它提供了专门的工厂类用于创建对象,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品。
抽象工厂模式(多个抽象产品类,增加抽象类),建造者模式,原型模式,适配器模式,策略模式等
详细参考:C# 软件开发模式、设计模式、设计原则和架构_c# 开发模式-CSDN博客
排序算法:选择排序,插入排序,冒泡排序,希尔排序,归并排序,快速排序,堆排序,基数排序,桶排序,基数排序 参考:https://blog.csdn.net/chenlong_cxy/article/details/116563972
哈希:是把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值,简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数(MD5,SHA-1)。
WPF技术
依赖属性:可以自己没有值,并能通过使用Binding从数据源获取值得属性
附加属性:实际上是一种依赖属性,把自己的属性附加给其他对象,使其他对象能引用该附加属性。(如Grid.row)
Binding(绑定):数据绑定是在应用 UI 与其显示的数据之间建立连接的过程。它是UI与数据逻辑之间的桥梁,实现了UI与数据逻辑的解耦。
路由事件:WPF的UI是由布局组件和控件构成的树形结构,当这颗树的某个节点激发出某个事件时,事件就会在UI组件树沿着一定方向传递下去,路由事件是沿着Visual Tree传递的,这样才让"藏"在Template里的控件把消息送出来。
Entity Framework(EF):微软官方提供的ORM工具,ORM让开发人员节省数据库访问的代码时间,将更多的时间放到业务逻辑层代码上。EF提供变更跟踪、唯一性约束、惰性加载、查询事物等。开发人员使用Linq语言,对数据库操作如同操作Object对象一样省事。
EF有三种使用场景,1. 从数据库生成Class,2.由实体类生成数据库表结构,3. 通过数据库可视化设计器设计数据库,同时生成实体类。对应三种编程方式:
1.DataBase First:在设计器中逆向生成Model,并有Model自动生成所有的类。
2.Model First:在设计器中创建Model,并用Model生成数据库。所有的类由Model自动生成。
3.Code First(又分New DataBase,Existing DataBase):代码优先,同Model First方式,区别在于不再需要EDM文件,所有的映射通过“数据注释”和“fluent API”进行映射和配置,"Code First"并不代表一定就必须通过数据类来定义模型,事实上也可以通过现有数据库生成数据类。
ORM:对象关系映射,是将数据存储从域对象自动映射到关系型数据库的工具。ORM主要包括3个部分:域对象、关系数据库对象、映射关系。ORM使类提供自动化CRUD,使开发人员从数据库API和SQL中解放出来。
EF优缺点:
优点:
1.简洁的Linq to Sql语句大大提高了开发人员的效率,不要再写复杂的sql语句;
2.不再需要再管应用程序如何去连接数据库;
3.EF可以用作用于数据服务和OData Service的基础设施;
缺点:
1.由于linq语句编译之后就是sql,对于这种自动生成的sql语句无法控制;
2.EF的运行机制会消耗大量内存,大大降低了程序运行效率,从而导致降低了用户在客户端的体验效果;
3.一旦数据结构发生变化,需要更新EF数据model;有时还可能会出现找不到更新过的实体类这种情况;
UML(统一建模语言):一个支持模型化和软件系统开发的图形化语言,为软件开发的所有阶段提供模型化和可视化支持,包括由需求分析到规格,到构造和配置。
测试
测试分类:单元测试(对单独的代码块分别进行测试,常用assert(断言)代码),集成测试,系统测试。
测试用例(Test Case):是指对一项特定的软件产品进行测试任务的描述,体现测试方案、方法、技术和策略。其内容包括测试目标、测试环境、输入数据、测试步骤、预期结果、测试脚本等,最终形成文档。简单地认为,测试用例是为某个特殊目标而编制的一组测试输入、执行条件以及预期结果,用于核实是否满足某个特定软件需求。
黑盒测试:又名为功能测试,主要目的是发现软件设计的需求或者是软件设计规格说明书中的错误缺陷。将程序看成不能打开的黑盒子,不考虑程序内部结构和特性的基础上通过程序接口进行测试,检查程序功能是否按照设计需求以及说明书的规定能够正常打开使用(),测试方法:等价类划分法,边界值分析法,因果图法,错误推测法。
白盒测试:白盒测试也称为结构测试,主要用于检测软件编码过程中的错误。程序员的编程经验、对编程软件的掌握程度、工作状态等因素都会影响到编程质量,导致代码错误。
Web技术
HTTP:超文本传输协议,HTTPS增加了SSL/TLS加密数据包,对网站服务器进行身份验证。
HTML5:超文本标记语音,是新版HTML,拥有新的语法、图形、多媒体元素和API,简化了web应用程序搭建。
CSS:叠层样式表,实现格式与结构分离,页面布局,实现多个网页同时更新样式。
内部样式合适:<style>
外部格式:<link>
脚本:按照一定格式编写的可行性文件。
Javascript:用于网页交互的脚本语言,基于对象,事件驱动。以<script src="">开头。
jQuery:javascript库。语法:$(selector).action();
AOP(面向切面编程):oAuth(API访问授权的开发标准),OData(开放数据协议),OA:办公自动化
IOC(控制反转)与DI(依赖注入):设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制,减少耦合。参考:https://www.cnblogs.com/atomy/p/12516304.html
.Net Core主机:是一个封装了应用资源的对象,负责web应用启动和生存周期管理,配置服务器和请求处理管道,配置日志,依赖关系注入
中间件:是封装到应用程序管道中以处理请求和响应的软件。
MVC模式:及模型,视图,控制器。模型:MVC需要提供的数据源,负责数据的访问和维护。视图:用于显示模型中数据的用户界面。
控制器:用来处理用户的输入,负责改变模型的状态并选择适当的视图来显示模型的数据。
MVVM模式:MVVM是Model-View-ViewModel的简写。它本质上就是MVC (Model-View- Controller)的改进版。即模型-视图-视图模型。【模型】指的是后端传递的数据。【视图】指的是所看到的页面。【视图模型】mvvm模式的核心,它是连接view和model的桥梁。它有两个方向:一是将【模型】转化成【视图】,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。二是将【视图】转化成【模型】,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。这两个方向都实现的,我们称之为数据的双向绑定。
Web消息队列:消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题。实现高性能,高可用,可伸缩和最终一致性架构。是大型分布式系统不可缺少的中间件。目前在生产环境,使用较多的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ等。
Web高并发解决方案:分离,缓存,HTML静态,数据库集群,CDN加速技术。
Web缓存:数据库缓存(redis),服务器缓存,客户端缓存(浏览器缓存.) URL:https://zhuanlan.zhihu.com/p/90507417
内存管理:1.减少无用的堆数据 2.及时释放和回收资源(如:dispose,using) 3.检测内存泄漏. 4.注意代码编写时少产生垃圾,比如String + String就会产生大量的垃圾,建议使用StringBuilder。
.Net Core注入方式:1.构造函数注入 2.view注入 3.通过 HttpContext来获取实例 4.直接注入
.Net Core常用注入:1.ConfigureServices 2.SuppressModelStateInvalidFilter 3.AddControllers 4.AddControllersAsServices 5.AddNewtonsoftJson 6.AddHttpContextAccesso
RibbitMQ(队列):
1、生产者+消费者(one to one,多对一) 生产者,Exchange,Queue,消费者
流程:生产一个RibbitMQ工厂,连接MQ,添加一个信道,定义一个队列,定义一个Exchange,信道绑定队列和Exchange,信道里面写数据,消费类似
2、发布+订阅(一对多)
流程:生产一个RibbitMQ工厂,连接MQ,添加一个信道,定义多个队列,定义一个Exchange,信道绑定队列和Exchange,信道里面写数据,消费类似
过滤器:
1、Authorization过滤器
2、Resource过滤器
3、Action过滤器
4、Exception过滤器
5、Result过滤器
领域驱动设计架构:表现层(mvc,api),应用层(针对用户应用场景,用例设计应用层服务,隔离底层细节),领域层(专注维护用户规则),基础设施层(负责数据查询和持久化)
SOA架构:界面层,业务逻辑层,数据引用层,领域驱动设计:展现层,应用层,领域层,基础设施层
C++技术
句柄(handle):是一个用来标识对象或者项目的标识符,可以用来描述窗体、文件等,值得注意的是句柄不能是常量,Windows之所以要设立句柄,根本上源于内存管理机制的问题,即虚拟地址。简而言之数据的地址需要变动,变动以后就需要有人来记录、管理变动,因此系统用句柄来记载数据地址的变更。在程序设计中,句柄是一种特殊的智能指针,当一个应用程序要引用其他系统(如数据库、操作系统)所管理的内存块或对象时,就要使用句柄.
好处:
1、我们可以在实现中用尺寸大小固定的(constant-sized)对象来表示尺寸大小不定的(variable-sized)值
2、我们可以在实现中用运行时绑定(run-time bounding)而不是编译时(compile-timebounding)绑定的方式来处理对象
3、对于实现的改变通常只会引起一次重新链接,而不是重新编译
4、我们可以对他人隐藏对象的实现
面试常见问题
网络协议分层?
物理层,数据链路层,网络层,传输层,会话层,表示层,应用层
举例你在项目中使用的设计模式?
什么是单例的懒汉与饥饿?
饥饿式天生就是线程安全的,先实例化。
private static Singleton _singleton = new Singleton();
public static Singleton GetInstance() { return _singleton;}
懒汉式本身是非线程安全的,后实例化。
private static Singleton _singleton = null;
public static Singleton GetInstance() { if(_singleton;}==null) _singleton = new Singleton(); return _singleton;}
TCP/IP的三次握手过程?
客户端发送syn报文,并置发送序列号X给服务端,服务端接收后发送syn报文+ack回应,并置发送序号为Y,再确认需要为ack=X+1,客户端接受后发送ack报文,并置发送序号为Z,在确认序号为ack=Y+1。
TCP与UDP区别?
1.TCP是面向连接的协议,必需经历三次握手才能建立连接,UDP是非连接协议,传输数据前不需要建立连接。及TCP协议可靠,UDP协议不可靠
2.TCP只能是点对点,UDP支持一对一,一对多,多对多。
3.TCP面向字节流,UDP面向报文。
4.UDP比TCP传输速度快
TCP应用场景:对数据完整度,安全性比较高
UDP应用场景:大量客户端,要求速度快,消息短,对安全性无特殊要求。
thread 与task区别?
- thread是单线程,task是多线程 单线程只能一核多任务,多线程能多核多任务.
- task可以使用取消令牌来支持取消,thread不能取消.
- task一个任务可以执行多个线程,thread只能执行一个线程.
- task可以使用async和await关键字轻松实现异步
- task可以直接返回结果
- task默认是后台线程,thread默认是前台线程(前台线程会阻止进程关闭,后台线程随进程关闭而关闭).
.Net Core处理流程?
Http Request--服务器--IIS/Nginx反向代理--kestrel(web服务器)--主机--Pipeline管道--各种中间件--终端中间件--各种中间件--返回
.Net Core托管种类和区别?
进程内托管:IIS工作进程中托管.net core应用程序。
进程外托管:外部服务器(IIS/Appache等)+内部服务器(kestrel)
常用的中间件?
- UseDeveloperExceptionPage//异常页面
- UseDefaultFiles//默认文件中间件
- UseStaticFiles//使用静态文件
- UseMvcDefaultRoute//使用默认路由mvc
- UseSession//使用session
IOC与DI是什么,已经它们的区别?
IOC:将主动权从程序代码本身反转到外部容器,将对象的创建,初始化,注销等工作交给soring容器来做,由spring容器控制对象生命周期,即将new 的过程交给spring容器处理。
DI:依赖注入是一种软件设计模式,指一个或多个依赖(或服务)被注入,或通过引用传递,传入一个依赖对象(或客户端)并成为客户状态的一部分。该模式通过自身的行为分离了客户依赖的创建。
谁依赖谁?
对象依赖IOC/DI的容器
为什么依赖:
对象需要IOC/DI的容器来提供对象所需外部资源
谁注入谁?
IOC/DI的容器注入某个对象
注入什么?
注入某个资源所需外部资源
谁控制谁?
IOC/DI的容器控制对象
控制什么?
控制对象实例创建
区别:
描述角度不一样,DI描述应用程序依赖容器创建并注入它所需的外部资源;IOC描述容器控制应用程序,由容器反向的向应用程序注入应用程序所需外部资源。DI是IOC的特定实现。
内存泄漏解决方案?
1.检测未退订的事件
2.静态变量(不手动处理是不会释放内存,减少使用)
3.非托管资源手动回收资源
4.Dispose方法没被调用
5.当一个查询语句查询出来的数据量很大,达到几百万条数据时存放到datatable 或dataset中也会造成内存溢出,这是可以采用分页查询等其他方法来解决
Note:托管资源和非托管资源:托管资源.net自动回收, 非托管资源指的是.NET不知道如何回收的资源,最常见的一类非托管资源是包装操作系统资源的对象,例如文件,窗口,网络连接,数据库连接,画刷,图标等。Microsoft为非托管资源的回收专门定义了一个接口:IDisposable,接口中只包含一个Dispose()方法。
参考:https://www.cnblogs.com/bile/p/4966796.html https://blog.csdn.net/zlwzlwzlw/article/details/7918633
海量数据库优化?
1.选择正确的存储引擎, MySQL为例,包括有两个存储引擎 MyISAM 和 InnoDB
2.优化字段的数据类型
3.为搜索字段添加索引
4.避免使用Select *
5.使用 ENUM 而不是 VARCHAR:ENUM 类型是非常快和紧凑的。在实际上,其保存的是 TINYINT,但其外表上显示为字符串。
6.尽可能的使用 NOT NULL
7.固定长度的表会更快
8.垂直分割:“垂直分割”是一种把数据库中的表按列变成几张表的方法
9.EXPLAIN 你的 SELECT 查询:使用 EXPLAIN 关键字可以让你知道MySQL是如何处理你的SQL语句的
10.使用缓存(Nosql,Redis)
11.提升硬件
缓存原理
- 检查用户请求的数据时缓存中是否存在,若存在直接返回,无需查询数据库。
- 若请求数据在缓存中查询不到,去查询数据库,返回数据,同时把数据存储到缓存中一份。
- 保持缓存的“新鲜性”,每当数据发生变化的时候,要同步更新缓存的信息,确保用户不会在缓存取到旧的数据。