数据库 C C++ 操作系统 计算机网络 笔记

数据库

参考MySQL索引背后的数据结构及算法原理

B-TREE 和 B+-TREE 区别

  • B-TREE:所有节点都存储数据,即所有节点的数据结构相同。
  • B+-TREE:只有叶节点存储数据,其他节点存储键值。

InnoDB MyISAM 区别

  • 用MyISAM建表时可以不设主键。
    InnoDB建索引树时必须按主键排序,故必须有主键。建表时若不指定主键,InnoDB选择可作唯一标识的列为主键。若无符合条件的列,则自动生成隐含字段作为主键,6字节。

  • MyISAM是非聚类的,其叶节点只存储Primary Key和数据的地址。
    InnoDB是聚类的,其叶节点存储完整的数据。

  • InnoDB的辅助索引的树,只存储辅助索引和主键。因此搜索时,先根据辅助索引找到对应主键,再搜索主键对应的数据。

优化

  • 考虑到MyISAM和InnoDB的不同性质,(在游戏业务中)可把业务分为两类:第一,访问量大且聚集在对当日数据的查询,第二,访问量较小且散布在历史数据的查询
    第一种情况适用InnoDB,因为InnoDB建的树是聚类的,其查找效率高,能满足大量访问。不过由于它的数据都存在叶节点,故这棵树会相对较大,但是相对于要管理大量历史数据的情况,只管理当日生成的数据所占的磁盘空间相对小,故问题不大。
    第二种情况,在访问量不大,但要管理庞大的历史数据的情况下,可以用MyISAMMyISAM的查询效率相对低点,不过对于访问量不大的情况已经足够。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执行上面两条查询语句所耗的时间:
用left()取字符串左部分,和用LIKE取左部分的区别

  • 再如,把
 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):
这里写图片描述
为提升效率,除了增加辅助索引<emp_no, from_date>,还可以用“隔离列”的方法:

首先查找中间的属性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,这就会比“隔离列”慢很多。
填坑结果比较

  • 创建表的时候把属性设为NOT NULL,这样数据库在搜索时就不用检查其是否为NULL。
  • 尽量不要 SELECT *,而是指定要选哪一列。即选取列的数量尽可能少。

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<A> v(5); // v.size() = 5
    cout << v[0].x; // legal, v[0].x会被vector初始化为0
}

lambda函数

语法:

[captures] (params) -> returnType { body }

用在sort()中的优势

在C中,example:

#include <stdlib.h>
#include <stdio.h>

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*)

在C++中,example:

#include <algorithm>
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;
}

sort()是模板,会保留所有类型信息。
方便简洁。

[ ]的用法

在函数主体中声明的 lambda 表达式可以捕获在声明 lambda 处可见的函数的任何局部变量。
中括号[]中可传入特定的变量(传值,即传副本,不可被更改),如:

void scan(function<void(void)> process) {
    process();
}

int main() {
    int a = 10;
    scan([a]()->void { cout << "lambda: " <<  a; }); // 把a的副本传给lambda函数,lambda中的a不可更改
    system("pause");
}

也可写为[=],也是传副本,不可更改。
若传入的值多了,会产生大量开销。

[&]是传引用

声明lambda函数:

auto foo = [] () { cout << "execute foo\n"; };
foo();

function模板

头文件<functional>
示例:

#include<iostream>
#include<functional>
using namespace std;

void scan(int* a, int length, function<void(int)> process)
{
    cout << "begin scan\n";
    for (int i = 0; i<length; i++) {
        process(a[i]);
    }
    cout << "end scan\n";
}
void f(int) {};

int main() {
    int a[10];
    scan(a, 10, f);
    scan(a, 10, [](int k)->void { 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 = ?
}

x = 32

例2

int main() {
    int a = 1, n = 10;
    cout << (++a*n++) << endl;
}

输出20

例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;
}

相当于a < b ? a : (c < d ? c : d)

操作系统篇

进程调度准则

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

Response time

amount of time it takes from when a request was submitted until the first response is produced, not output (for time-sharing environment)

待解决

非对称加密算法有哪些
在客户端/服务端加密?
TCP粘包 长连接短连接
堆排序 选择排序 插入排序 稳定性
unordered_map实现
线程和进程的区别
有split这个函数吗
虚存管理和实存管理的区别
static函数与普通函数区别
数据库如何查重
数据库查询变慢了,如何加快
如何知道发生了内存泄漏
pair的实现
萃取
智能指针(自动delete)
键盘敲字,进程不会中断
C++11 17新特性
STL tuple
内存的专业名词

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值