数据库知识学习之C C++ 操作系统、计算机网络等
b-tree 和 b+-tree 区别
b-tree:所有节点都存储数据,即所有节点的数据结构相同。 b+-tree:只有叶节点存储数据,其他节点存储键值。
innodb myisam 区别
用myisam建表时可以不设主键。
innodb建索引树时必须按主键排序,故必须有主键。建表时若不指定主键,innodb选择可作唯一标识的列为主键。若无符合条件的列,则自动生成隐含字段作为主键,6字节。
myisam是非聚类的,其叶节点只存储primary key和数据的地址。
innodb是聚类的,其叶节点存储完整的数据。
innodb的辅助索引的树,只存储辅助索引和主键。因此搜索时,先根据辅助索引找到对应主键,再搜索主键对应的数据。
优化
考虑到myisam和innodb的不同性质,(在游戏业务中)可把业务分为两类:第一,访问量大且聚集在对当日数据的查询,第二,访问量较小且散布在历史数据的查询。
第一种情况适用innodb,因为innodb建的树是聚类的,其查找效率高,能满足大量访问。不过由于它的数据都存在叶节点,故这棵树会相对较大,但是相对于要管理大量历史数据的情况,只管理当日生成的数据所占的磁盘空间相对小,故问题不大。
第二种情况,在访问量不大,但要管理庞大的历史数据的情况下,可以用myisam。myisam的查询效率相对低点,不过对于访问量不大的情况已经足够。myisam的非聚类树的叶节点只存储键值和数据的地址,故树所占空间相对小。 查询中能不用表达式或函数就不用,因为某一列用表达式或函数时,mysql就不会对该列用索引搜索,进而影响后面的索引。如
select * from employees.titles where emp_no='10001' and left(title, 6)='senior';
最好不要用left()函数,应该改为
select * from employees.titles where emp_no='10001' and title like 'senior%'
这样查询速度会提升。下图可见mysql执行上面两条查询语句所耗的时间:
再如,把喎? f/ware/vc/"="" target="_blank" class="keylink">vcd4ncjxwcmugy2xhc3m9"brush:java;"> select * from employees.titles where emp_no - 1='10000';
改为
select * from employees.titles where emp_no='10001';
能提升查询速度。(常量运算尽量先自己算好,转为无表达式的查询语句,再查询)
innodb主键不宜过长,因为所有辅助索引都使用主键,过长会导致辅助索引的树过大。 用非单调字段作为innodb主键不好,因为频繁地插入删除会导致索引树的频繁分裂与合并。 若你会对某个属性进行频繁查找,可将其设为辅助索引(secondary key)。 查询条件用到了索引中列的精确匹配,但是中间某个条件未提供。
例如有如下表
create table titles ( emp_no int not null, title varchar(50) not null, from_date date not null, to_date date, primary key (emp_no,title, from_date) ) ;
当执行
explain select * from employees.titles where emp_no='10001' and from_date='1986-06-26';
后,可见查询只用到了索引第一个属性emp_no,而from_date并未用到(key_len只有4. 而整个primary key的长度为59):
为提升效率,除了增加辅助索引
首先查找中间的属性title有什么值,得到'senior engineer', 'staff', 'engineer', 'senior staff', 'assistant engineer', 'technique leader', 'manager'。那就把上面查询改为
select * from employees.titles
where emp_no='10001' and title in ('senior engineer', 'staff', 'engineer', 'senior staff', 'assistant engineer', 'technique leader', 'manager') and from_date='1986-06-26';
给索引中间“填上坑”。
下图给出“未填坑”和“填坑”后的时间比较,可见“填坑”后是快了点。这适用在title属性的值不会太多的情况。如果通过先比较emp_no得到大量的数据,再从中筛选得到想要的from_date,这就会比“隔离列”慢很多。
c++篇
const变量存储位置
编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高
struct & class
c++中的struct是对c中的struct的扩充。和class一样,struct有自己的成员函数、构造函数和析构函数,能继承,能实现多态。
区别:
默认继承方式不一样。class默认继承方式为private,struct默认继承方式为public;
访问方式不同。class默认成员为private,struct默认其数据为public;
概念上的区别:
class对应于对象,其包含成员变量;
struct对应于数据结构,其包含数据。
virtual 析构函数
析构函数设为virtual,当父类指针指向new 子类时,delete父指针,会自动识别调用子类析构函数,否则只会调用父类析构函数。
函数名 & 函数签名
函数名:函数的名称
函数签名:包括函数名、参数类型、函数所在的类和名称空间及其他信息
数组指针 & 指针数组
数组指针:
int (*p)[4]; // 由4个元素所组成的数组指针 int a[3][4]; p = a; // p + 1指向的是数组第1行(从0数起)
int* p[4]; // 是指针数组
指针函数&函数指针
指针函数:返回一个指针的函数
void *getgate(int id)
函数指针:指向函数的指针包含了函数的地址,可通过它来调用函数
int (*fptr)(int id);
字节对齐
class a { int x; char ch[5]; int get() { return x; } };
sizeof(a) = 12
长度都是4字节的倍数
cpu每个时钟从内存读取4字节。若存储的数据跨字节,如double类型,则要用两个clock读取,降低效率。(觉得是因为,在32位机器中,每个寄存器都是32位的,估每次读取4个字节)
初始化
实例化一个类,编译器不会自动将其初始化;
但是vector会初始化(int char等设为0,类中的成员都设为0)
class a { public: int x; }; int main() { a a; cout << a.x; // illegal,x未被初始化,vs报错 vector v(5); // v.size() = 5 cout << v[0].x; // legal, v[0].x会被vector初始化为0 }
lambda函数
语法:
[captures] (params) -> returntype { body }
用在sort()中的优势
#include #include static int intcompare(const void *p1, const void *p2) { int i = *((int *)p1); int j = *((int *)p2); return (i < j) ; } int main() { int a[10] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; qsort((void *)a, 10, sizeof (int), intcompare); for (int i = 0; i < 10; i++) { printf("%d ", a[i]); } printf("\n"); return 0; }
缺点:需要在函数体外定义函数static int compare(const void* a, const void* b),且无法对参数的类型进行检查(因为参数类型是void*)
#include int main() { int a[10] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; std::sort( a, &a[10], [](int x, int y){ return x < y; } ); for(int i=0; i<10; i++) { printf("%i ", a[i]); } printf("\n"); return 0; }
[ ]的用法
在函数主体中声明的 lambda 表达式可以捕获在声明 lambda 处可见的函数的任何局部变量。
中括号[]中可传入特定的变量(传值,即传副本,不可被更改),如:
void scan(function process) { process(); } int main() { int a = 10; scan([a]()->void { cout << "lambda: " << a; }); // 把a的副本传给lambda函数,lambda中的a不可更改 system("pause"); }
也可写为[=],也是传副本,不可更改。
若传入的值多了,会产生大量开销。
auto foo = [] () { cout << "execute foo\n"; }; foo();
function模板
#include #include using namespace std; void scan(int* a, int length, function process) { cout << "begin scan\n"; for (int i = 0; ivoid { cout << "lambda: a: " << k << endl; }); system("pause"); }
begin scan end scan begin scan lambda: a: -858993460 lambda: a: -858993460 lambda: a: -858993460 lambda: a: -858993460 lambda: a: -858993460 lambda: a: -858993460 lambda: a: -858993460 lambda: a: -858993460 lambda: a: -858993460 lambda: a: -858993460 end scan
例1
int main() { int x, y, z, k; x = (y = 4, z = 16, k = 32)++; x = }
例2
int main() { int a = 1, n = 10; cout << (++a*n++) << endl; }
例3
int main() { char* p[5] = { "abcd", "abcde", "abcdefg", "abcdefghi", "ab" }; }
编译不通过,报错内容为不能用const char*(“abcd”等是const char*) 来初始化char* 类型的变量。要在char* p[5]前加const
例4
int main() { int a = 50, b = 20, c = 30, d = 2; cout << (a < b a : c < d c : d) << endl; }
进程调度准则
cpu utilization
keep the cpu as busy as possible
throughput 吞吐量
number of processes that complete their execution per time unit单位时间完成进程数
turnaround time 周转时间
amount of time to execute a particular process
waiting time
amount of time a process has been waiting in the ready queue