1.内存模型:C++的内存可以分成5个区域
(1) 堆(heap) :可以使用new和malloc来申请内存,但必须在不使用的时候使用delete和free释放掉
(2) 栈(stack):这个区域是有编译器自动申请和释放的,栈中存放着局部变量,函数参数,局部常量。栈一般比较小,栈不仅要放函数递归调用的参数,还需要放一些函数内部的参数,本身的开销就比较大,容易栈溢出。
(3) 静态存储区:主要存储全局静态变量,局部静态变量,全局变量,以及虚函数表。
(4) 常量存储区:主要保存全局常量,常量数组,函数指针。
(5) 代码区:就是存放代码的地方,这个就不多说,实际上就是一个只读的区域,和常量区一样,只是这个区域的指针可以执行
2.C++多线程内存模型
C++程序员要想写出高性能的多线程程序必须理解内存模型,编译器会给你的程序做优化(静态),CPU为了提升性能也有乱序执行(动态),总之,程序在最终执行时并不会按照你之前的原始代码顺序来执行。为了更容易的进行多线程编程,程序员希望程序能按照顺序一致性模型执行;但是顺序一致性对性能的损失太大了,CPU和编译器为了提高性能就必须要做优化
这个模型约定:
程序员只需要恰当地使用具有同步语义的指令来标记那些真正需要同步的变量和操作,就相当于告诉CPU和编译器不要对这些标记好的同步操作和变量做违反顺序一致性的优化,而其它未被标记的地方可以做原有的优化。编译器和CPU的大部分优化手段都可以继续实施,只是在同步原语处需要对优化做出相应的限制;而且程序员只需要保证正确地使用同步原语即可,因为它们最终表现出来的执行效果与顺序一致性模型一致。由此,C++多线程内存模型帮助我们在易编程性和性能之间取得了一个平衡。
一.为什么用自增列作为主键
1.自增主键确保主键非空;
如果我们定义了主键(PRIMARY KEY),那么InnoDB会选择主键作为聚集索引。
如果没有显式定义主键,则InnoDB会选择第一个不包含有NULL值的唯一索引作为主键索引。
如果也没有这样的唯一索引,则InnoDB会选择内置6字节长的ROWID作为隐含的聚集索引(ROWID随着行记录的写入而主键递增,这个ROWID不像ORACLE的ROWID那样可引用,是隐含的)。
2.自增主键确保新插入的节点在当前索引节点的后续位置,否则会为了将新记录查到合适的位置而移动其他记录,移动、分页操作造成了大量的碎片,得到了不够紧凑的索引结构。
数据记录本身被存于主索引(一颗B+Tree)的叶子节点上,这就要求同一个叶子节点内(大小为一个内存页或磁盘页)的各条数据记录按主键顺序存放,因此每当有一条新的记录插入时,MySQL会根据其主键将其插入适当的节点和位置,如果页面达到装载因子(InnoDB默认为15/16),则开辟一个新的页(节点)。如果表使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的页。
二。为什么使用数据索引能提高效率
-
数据索引的存储是有序的
-
在有序的情况下,通过索引查询一个数据是无需遍历索引记录的
-
极端情况下,数据索引的查询效率为二分法查询效率,趋近于 log2(N)
三。什么情况下应不建或少建索引
1.表记录太少
2.经常插入、删除、修改的表
3.经常和主字段一块查询但主字段索引值比较多的表字段
4.数据重复且分布平均的表字段,比如性别可能就只有两个值,建索引不仅没什么优势,还会影响到更新速度,这被称为过度索引
在对建立索引的时候要对表进行加锁,因此应当注意操作在业务空闲的时候进行。
四:索引的性能调整
索引与数据分散到不同的磁盘上(不考虑阵列的情况)。逻辑上,数据表空间与索引表空间分开。这是在建索引时应当遵守的基本准则。
再次,建立索引除了要进行全表扫描外同时还要对数据进行大量的排序操作,因此,应当调整排序区的大小
最后,建立索引的时候,可以加上nologging选项。以减少在建立索引过程中产生的大量redo,从而提高执行的速度。
五.索引优化
1.创建复合索引,
select * from users where area=’beijing’ and age=22;
如果我们是在area和age上分别创建单个索引的话,由于mysql查询每次只能使用一个索引,所以虽然这样已经相对不做索引时全表扫描提高了很多效
率,但是如果在area、age两列上创建复合索引的话将带来更高的效率。如果我们创建了(area, age,
salary)的复合索引,那么其实相当于创建了(area,age,salary)、(area,age)、(area)三个索引,这被称为最佳左前缀
特性。因此我们在创建复合索引时应该将最常用作限制条件的列放在最左边,依次递减。
mysql查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。
2.短索引
对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的 列,如果在前10 个或20 个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。
3.like语句操作
一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引而like “aaa%”可以使用索引。
4.不要在列上进行运算 select * from users where YEAR(adddate);
六.B+树索引和哈希索引的区别
B+树是一个平衡的多叉树,从根节点到每个叶子节点的高度差值不超过1,而且同层级的节点间有指针相互链接,是有序的。
哈希索引就是采用一定的哈希算法,把键值换算成新的哈希值,检索时不需要类似B+树那样从根节点到叶子节点逐级查找,只需一次哈希算法即可,是无序的
哈希索引不适用的场景:
-
不支持范围查询
-
不支持索引完成排序
-
不支持联合索引的最左前缀匹配规
如果存储的数据重复度很低(也就是说基数很大),对该列数据以等值查询为主,没有范围查询、没有排序的时候,特别适合采用哈希索引,例如这种SQL: 等值查询:select id, name from table where name='李明';
七.
而常用的 InnoDB 引擎中默认使用的是B+树索引,它会实时监控表上索引的使用情况。
如果认为建立哈希索引可以提高查询效率,则自动在内存中的“自适应哈希索引缓冲区”建立哈希索引(在InnoDB中默认开启自适应哈希索引)。
通过观察搜索模式,MySQL会利用index key的前缀建立哈希索引,如果一个表几乎大部分都在缓冲池中,那么建立一个哈希索引能够加快等值查询。
注意:在某些工作负载下,通过哈希索引查找带来的性能提升远大于额外的监控索引搜索情况和保持这个哈希表结构所带来的开销。
但某些时候,在负载高的情况下,自适应哈希索引中添加的read/write锁也会带来竞争,比如高并发的join操作。like操作和%的通配符操作也不适用于自适应哈希索引,可能要关闭自适应哈希索引。
八。B树和B+树的区别
1、B树,每个节点都存储key和data,所有节点组成这棵树,并且叶子节点指针为nul,叶子结点不包含任何关键字信息。
2、B+树,所有的叶子结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大的顺序链接。
九、为什么说B+比B树更适合实际应用中操作系统的文件索引和数据库索引?
1、B+的磁盘读写代价更低。
B+的内部结点并没有指向关键字具体信息的指针,因此其内部结点相对B树更小。关键字存放在同一页中,一次性读入内存中的需要查找的关键字也就越多。相对来说IO读写次数也就降低了。
2、B+-tree的查询效率更加稳定。
由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。
十、表分区?
表分区,是指根据一定规则,将数据库中的一张表分解成多个更小的,容易管理的部分。从逻辑上看,只有一张表,但是底层却是由多个物理分区组成。一个表最多只能有1024个分区.如果分区字段中有主键或者唯一索引的列,那么多有主键列和唯一索引列都必须包含进来。即:分区字段要么不包含主键或者索引列,要么包含全部主键和索引列
分表:指的是通过一定规则,将一张表分解成多张不同的表。比如将用户订单记录根据时间成多个表。
分表与分区的区别在于:分区从逻辑上来讲只有一张表,而分表则是将一张表分解成多张表。
表分区好处:
1、存储更多数据。分区表的数据可以分布在不同的物理设备上,从而高效地利用多个硬件设备。和单个磁盘或者文件系统相比,可以存储更多数据
2、优化查询。在where语句中包含分区条件时,可以只扫描一个或多个分区表来提高查询效率;涉及sum和count语句时,也可以在多个分区上并行处理,最后汇总结果。
3、分区表更容易维护。例如:想批量删除大量数据可以清除整个分区。
分区表的限制因素
1.分区表中无法使用外键约束
2.MySQL的分区适用于一个表的所有数据和索引,不能只对表数据分区而不对索引分区,也不能只对索引分区而不对表分区
3。如果分区字段中有主键或者唯一索引的列,那么多有主键列和唯一索引列都必须包含进来。即:分区字段要么不包含主键或者索引列,要么包含全部主键和索引列。
十一:外键约束:
外键对应的是参照完整性,一个表的外键可以为空值,若不为空值,则每一个外键的值必须等于另一个表中主键的某个值。
外键是表的一个字段,不是本表的主键,但对应另一个表的主键。定义外键后,不允许删除另一个表中具有关联关系的行。
外键的主要作用是保持数据的一致性、完整性。例如,部门表 tb_dept 的主键是 id,在员工表 tb_emp5 中有一个键 deptId 与这个 id 关联。
- 主表(父表):对于两个具有关联关系的表而言,相关联字段中主键所在的表就是主表。
- 从表(子表):对于两个具有关联关系的表而言,相关联字段中外键所在的表就是从表。
创建 tb_dept1 的 SQL 语句运行结果如下所示。
mysql> CREATE TABLE tb_dept1
-> (
-> id INT(11) PRIMARY KEY,
-> name VARCHAR(22) NOT NULL,
-> location VARCHAR(50)
-> );
Query OK, 0 rows affected (0.37 sec)
创建数据表 tb_emp6,并在表 tb_emp6 上创建外键约束,让它的键 deptId 作为外键关联到表 tb_dept1 的主键 id,输入的 SQL 语句和运行结果如下所示。
mysql> CREATE TABLE tb_emp6
-> (
-> id INT(11) PRIMARY KEY,
-> name VARCHAR(25),
-> deptId INT(11),
-> salary FLOAT,
-> CONSTRAINT fk_emp_dept1
-> FOREIGN KEY(deptId) REFERENCES tb_dept1(id)
-> );
十二。MySQL支持的分区类型有哪些?
-
RANGE分区: 这种模式允许将数据划分不同范围。例如可以将一个表通过年份划分成若干个分区
-
LIST分区: 这种模式允许系统通过预定义的列表的值来对数据进行分割。按照List中的值分区,与RANGE的区别是,range分区的区间范围值是连续的。
-
HASH分区 :这中模式允许通过对表的一个或多个列的Hash Key进行计算,最后通过这个Hash码不同数值对应的数据区域进行分区。例如可以建立一个对表主键进行分区的表。
十三。四种隔离级别
-
Serializable (串行化):可避免脏读、不可重复读、幻读的发生。给数据加锁,强制事务排序。但会导致锁竞争和超时等待。
-
Repeatable read (可重复读):可避免脏读、不可重复读的发生。一个事务的多次读取数据得到的结果相同,但是中间可能会有新的数据插入。导致幻读,InoDB通过MVCC多版本并发控制解决了不可重复度。
-
Read committed (读已提交):可避免脏读的发生。一个事务只能读到其他事务已经提交的结果,看不到未提交的。
-
Read uncommitted (读未提交):最低级别,任何情况都无法保证。一个事务能读到其他事务未提交的结果(脏读)。
十四。mysql优化
1.对于大数据字段,独立表进行存储,以便影响性能(例如:简介字段);
2.使用varchar类型代替char,因为varchar会动态分配长度,char指定长度是固定的;
3.避免表字段运行为null,建议设置默认值(例如:int类型设置默认值为0)在索引查询上,效率立显;
4.为经常所搜的字段建立索引,最好建立在唯一和非空的字段上,建立太多的索引对后期插入、更新都存在一定的影响;
5.当只要一行数据时使用limit 1,引擎在找到一条数据后停止搜索,而不是继续往下搜索。
6.开启查询缓存,优化查询、
7.垂直分表
8.选择正确的存储引擎
十五、数据库表创建注意事项
1.字段命名要有规则及相对应的含义
2.字段不要大小写混用(想要具有可读性,多个英文单词可使用下划线形式连接)
3.字段名不要使用保留字或者关键字;
4.给文本字段留足余量
5.多型字段的处理,就是表中是否存在字段能够分解成更小独立的几部分(例如:人可以分为男人和女人);
6.多值字段的处理,可以将表分为三张表,这样使得检索和排序更加有调理,且保证数据的完整性!
十六.Mysql 中 MyISAM 和 InnoDB 的区别有哪些?
-
InnoDB支持事务,MyISAM不支持
对于InnoDB每一条SQL语言都默认封装成事务,自动提交,这样会影响速度,所以最好把多条SQL语言放在begin和commit之间,组成一个事务;
-
InnoDB支持外键,而MyISAM不支持。对一个包含外键的InnoDB表转为MYISAM会失败;
-
InnoDB是聚集索引,数据文件是和索引绑在一起的,必须要有主键,通过主键索引效率很高。
-
InnoDB不保存表的具体行数,执行select count(*) from table时需要全表扫描。而MyISAM用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快;
-
Innodb不支持全文索引,而MyISAM支持全文索
十七.行级锁定的优点:
1、当在许多线程中访问不同的行时只存在少量锁定冲突。
2、回滚时只有少量的更改
3、可以长时间锁定单一的行。
行级锁定的缺点:
-
比页级或表级锁定占用更多的内存。
-
当在表的大部分中使用时,比页级或表级锁定速度慢,因为你必须获取更多的锁。
-
如果你在大部分数据上经常进行GROUP BY操作或者必须经常扫描整个表,比其它锁定明显慢很多。
-
用高级别锁定,通过支持不同的类型锁定,你也可以很容易地调节应用程序,因为其锁成本小于行级锁定。
十八。事务的 ACID
事务具有四个特征:
原子性( Atomicity ):事务要么全做,要么不做,不能只执行一部分
一致性( Consistency ):事务执行的结果是使数据库从一个确定状态到另一个确定状态,不存在数据写到一半就中断的情况。
隔离性( Isolation ):事务之间是相互隔离的,互不干扰。
持续性( Durability ):事务提交的结果是永久的,不会因为其他故障发生对提交的结果产生影响。
19.慢查询
MySQL的慢查询,全名是慢查询日志,是MySQL提供的一种日志记录,用来记录在MySQL中响应时间超过阀值的语句。
具体环境中,运行时间超过long_query_time
值的SQL语句,则会被记录到慢查询日志中。
当然,如果不是调优需要的话,一般不建议启动该参数,因为开启慢查询日志会或多或少带来一定的性能影响。
关于运行时间正好等于long_query_time
的情况,并不会被记录下来。
1.查看是否开启慢查询日志
mysql> show variables like '%slow_query_log%';
2.如果你想查询有多少条慢查询记录,可以使用Slow_queries
系统变量。
mysql> show global status like '%Slow_queries%';
3.关于运行时间正好等于long_query_time
(微秒)的情况,并不会被记录下来,
mysql> show variables like 'long_query_time%';
4.慢查询日志输出格式
mysql> show variables like '%log_output%';
log_output='FILE'
表示将日志存入文件,默认值也是'FILE'
。
log_output='TABLE'
表示将日志存入数据库,这样日志信息就会被写入到mysql.slow_log
表中。
5.MySQL提供了日志分析工具mysqldumpslow
20.全局锁 表锁 悲观锁 乐观锁
1.全局锁就是对整个数据库实例加锁。MySQL 提供了一个加全局读锁的方法,命令是
:Flush tables with read lock (FTWRL)
。
:set global readonly=true
全局锁的典型使用场景是,做全库逻辑备份(mysqldump)。重新做主从时候 。为了保证备份数据库的数据一致性,在备份过程中整个库完全处于只读状态
2.悲观锁,总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,一般多写的场景下用悲观锁就比较合适。
3.乐观锁:总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于读多写少的应用类型,这样可以提高吞吐量。
1. 版本号机制
一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新。
2. CAS算法
即compare and swap(比较与交换),是一种有名的无锁算法。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。CAS算法涉及到三个操作数
需要读写的内存值 V
进行比较的值 A
拟写入的新值 B
当且仅当 V 的值等于 A时,CAS通过原子方式用新值B来更新V的值,否则不会执行任何操作(比较和替换是一个原子操作)。一般情况下是一个自旋操作,即不断的重试。
CAS算法存在ABA 问题
如果一个变量V初次读取的时候是A值,并且在准备赋值的时候检查到它仍然是A值,那我们就能说明它的值没有被其他线程修改过了吗?很明显是不能的,因为在这段时间它的值可能被改为其他值,然后又改回A,那CAS操作就会误认为它从来没有被修改过。这个问题被称为CAS操作的 "ABA"问题。
自旋CAS(也就是不成功就一直循环执行直到成功)如果长时间不成功,会给CPU带来非常大的执行开销。
CAS算法只能保证一个共享变量的原子操作。
21.mysql中的内置函数
数学函数:
abs(x)
mod(x,y)
sqrt(x)
rand(),rand(N):返回0-1间的浮点数,使用不同的seed N可以获得不同的随机数
round(x, D):四舍五入保留D位小数,D默认为0, 可以为负数, 如round(19, -1)返回20
sign(x): 返回x的符号,正负零分别返回1, -1, 0
pow(x,y)或者power(x,y)
log(x):自然对数
sin(x)
cos(x)
字符串函数:
ltrim(s):删除s左侧空格字符
char_length(str):返回str所包含的字符数,一个多字节字符算一个字符
length(str):返回字符串的字节长度,如utf8中,一个汉字3字节,数字和字母算一个字节
left(s,n):返回字符串s最左边n个字符
right(s,n): 返回字符串最右边n个字符
3 日期和时间函数
CURDATE()
EXTRACT(unit FROM date):提取日期时间中的要素
例如
SELECT EXTRACT(YEAR FROM '2009-07-02'); ##2009
SELECT EXTRACT(YEAR_MONTH FROM '2009-07-02 01:02:03');##200907
SELECT EXTRACT(DAY_MINUTE FROM '2009-07-02 01:02:03');##20102
FORMAT(X,D[,locale]):将数字X转化成'#,###,###.##'格式,D为保留的小数位数
MAX([DISTINCT] expr)
MIN([DISTINCT] expr)
SUM([DISTINCT] expr)
VERSION():返回mysql服务器的版本,是utf8编码的字符串
CONNECTION_ID():显示连接号(连接的线程号)
22.mysql视图
MySQL视图是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据。但是,视图并不在数据库中以存储的数据值集形式存在。行和列数据来自由定义视图的查询所引用的表,并且在引用视图时动态生成。MySQL视图的作用类似于筛选。定义视图的筛选可以来自当前或其它数据库的一个或多个表,或者其它视图。通过视图进行查询没有任何限制,通过它们进行数据修改时的限制也很少。
创建视图:
CREATE VIEW <视图名> AS <SELECT语句>;
查看视图:
DESCRIBE 视图名;
作用一:提高了重用性,就像一个函数。如果要频繁获取某些字段内容,就可以创建视图。
作用二:对数据库重构,却不影响程序的运行。
作用三:提高了安全性能。可以对不同的用户,设定不同的视图。例如:某用户只能获取user表的name和age数据,不能获取sex数据。则可以这样创建视图。示例如下:
create view other as select a.name, a.age from user as a;
作用四:让数据更加清晰。想要什么样的数据,就创建什么样的视图
23.内存表:
1. 参数控制:max_heap_table_size
2. 到达上限后报错。
3. 表定义保存在磁盘上,数据和索引保存在内存里面。当mysql重启之后,内存表的数据会丢失,表结构依旧存在。
4. 不能包含TEXT,BLOB等字段。
内存表对所有的用户连接都是可用的。这就意味着,多个会话连接的内存表名字不能重复,具有唯一性
临时表:
1. 参数控制:tmp_table_size。
2. 到达上限后创建文件在磁盘上,超出部分编成磁盘表。
3. 表定义和数据都在内存里。
4. 可以包含TEXT, BLOB等字段。
5.临时表只在当前连接可见,当这个连接关闭的时候,会自动drop。
create temporary table tmp_table(
name varchar(10) not null,
value int not null
);
对比一下内存表和临时表的一些主要区别吧
存储
内存表 表结构存储在磁盘中,数据存储在内存中
临时表 表结构和数据都存储在内存中
会话
内存表 是可以多个会话共享的
临时表 是单个会话独享的,是会话级别的
引擎
内存表默认,memory
临时表默认,myisam
断开连接
临时表 啥都不剩
内存表 只剩下表结构
性能
内存表由于所有的内容都是放在内存中,所以相对来说,速度较快但是同时数据的维护较为困难