如:

selectid fromt wherenum/ 2= 100

应改为:

selectid fromt wherenum = 100* 2;

不适合键值较少的列(重复数据较多的列)比如:set enum列就不适合(枚举类型(enum)可以添加null,并且默认的值会自动过滤空格集合(set)和枚举类似,但只可以添加64个值)

如果MySQL估计使用全表扫描要比使用索引快,则不使用索引

什么是聚集索引

B+Tree叶子节点保存的是数据还是指针

MyISAM索引和数据分离,使用非聚集

InnoDB数据文件就是索引文件,主键索引就是聚集索引

Redis命令总结

为什么这么快?

基于内存,由C语言编写

使用多路I/O复用模型,非阻塞IO

使用单线程减少线程间切换

因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了(毕竟采用多线程会有很多麻烦!)。

数据结构简单

自己构建了VM机制,减少调用系统函数的时间

优势

丰富的数据类型

原子 – Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行

什么是redis事务?

将多个请求打包,一次性、按序执行多个命令的机制

通过multi,exec,watch等命令实现事务功能

Python redis-py pipeline=conn.pipeline(transaction=True)

持久化方式

RDB(快照)

save(同步,可以保证数据一致性)

bgsave(异步,shutdown时,无AOF则默认使用)

AOF(追加日志)

怎么实现队列

push

rpop

常用的数据类型(Bitmaps,Hyperloglogs,范围查询等不常用)

String(字符串):计数器

整数或sds(Simple Dynamic String)

List(列表):用户的关注,粉丝列表

ziplist(连续内存块,每个entry节点头部保存前后节点长度信息实现双向链表功能)或double linked list

Hash(哈希):

Set(集合):用户的关注者

intset或hashtable

Zset(有序集合):实时信息排行榜

skiplist(跳跃表)

与Memcached区别

Memcached只能存储字符串键

Memcached用户只能通过APPEND的方式将数据添加到已有的字符串的末尾,并将这个字符串当做列表来使用。但是在删除这些元素的时候,Memcached采用的是通过黑名单的方式来隐藏列表里的元素,从而避免了对元素的读取、更新、删除等操作

Redis和Memcached都是将数据存放在内存中,都是内存数据库。不过Memcached还可用于缓存其他东西,例如图片、视频等等

虚拟内存–Redis当物理内存用完时,可以将一些很久没用到的Value 交换到磁盘

存储数据安全–Memcached挂掉后,数据没了;Redis可以定期保存到磁盘(持久化)

应用场景不一样:Redis出来作为NoSQL数据库使用外,还能用做消息队列、数据堆栈和数据缓存等;Memcached适合于缓存SQL语句、数据集、用户临时性数据、延迟查询数据和Session等

Redis实现分布式锁

使用setnx实现加锁,可以同时通过expire添加超时时间

锁的value值可以是一个随机的uuid或者特定的命名

释放锁的时候,通过uuid判断是否是该锁,是则执行delete释放锁

常见问题

缓存雪崩

短时间内缓存数据过期,大量请求访问数据库

缓存穿透

请求访问数据时,查询缓存中不存在,数据库中也不存在

缓存预热

初始化项目,将部分常用数据加入缓存

缓存更新

数据过期,进行更新缓存数据

缓存降级

当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级

一致性Hash算法

使用集群的时候保证数据的一致性

基于redis实现一个分布式锁,要求一个超时的参数

setnx

虚拟内存

内存抖动

Linux

Unix五种i/o模型

阻塞io

非阻塞io

多路复用io(Python下使用selectot实现io多路复用)

select

并发不高,连接数很活跃的情况下

poll

比select提高的并不多

epoll

适用于连接数量较多,但活动链接数少的情况

信号驱动io

异步io(Gevent/Asyncio实现异步)

比man更好使用的命令手册

tldr:一个有命令示例的手册

kill -9和-15的区别

-15:程序立刻停止/当程序释放相应资源后再停止/程序可能仍然继续运行

-9:由于-15的不确定性,所以直接使用-9立即杀死进程

分页机制(逻辑地址和物理地址分离的内存分配管理方案):

操作系统为了高效管理内存,减少碎片

程序的逻辑地址划分为固定大小的页

物理地址划分为同样大小的帧

通过页表对应逻辑地址和物理地址

分段机制

为了满足代码的一些逻辑需求

数据共享/数据保护/动态链接

每个段内部连续内存分配,段和段之间是离散分配的

查看cpu内存使用情况?

top

free 查看可用内存,排查内存泄漏问题

设计模式

单例模式

# 方式一
defSingle(cls,*args,**kwargs):
instances = {}
defget_instance(*args, **kwargs):
ifcls notininstances:
instances[cls] = cls(*args, **kwargs)
returninstances[cls]
returnget_instance
@Single
classB:
pass
# 方式二
classSingle:
def__init__(self):
print( "单例模式实现方式二。。。")
single = Single
delSingle # 每次调用single就可以了
# 方式三(最常用的方式)
classSingle:
def__new__(cls,*args,**kwargs):
ifnothasattr(cls, '_instance'):
cls._instance = super.__new__(cls,*args,**kwargs)
returncls._instance
工厂模式
classDog:
def__init__(self):
print( "Wang Wang Wang")
classCat:
def__init__(self):
print( "Miao Miao Miao")
deffac(animal):
ifanimal.lower == "dog":
returnDog
ifanimal.lower == "cat":
returnCat
print( "对不起,必须是:dog,cat")
构造模式
class Computer:
def __init__(self,serial_number):
self.serial_number = serial_number
self.memory = None
self.hadd = None
self.gpu = None
def __str__(self):
info = (f'Memory:{self.memoryGB}',
'Hard Disk:{self.hadd}GB',
'Graphics Card:{self.gpu}')
return ''.join(info)
class ComputerBuilder:
def __init__(self):
self.computer = Computer('Jim1996')
def configure_memory(self,amount):
self.computer.memory = amount
return self #为了方便链式调用
def configure_hdd(self,amount):
pass
def configure_gpu(self,gpu_model):
pass
class HardwareEngineer:
def __init__(self):
self.builder = None
def construct_computer(self,memory,hdd,gpu)
self.builder = ComputerBuilder
self.builder.configure_memory(memory).configure_hdd(hdd).configure_gpu(gpu)
@property
def computer(self):
return self.builder.computer
数据结构和算法内置数据结构和算法
python实现各种数据结构
快速排序
defquick_sort(_list):
iflen(_list) < 2:
return_list
pivot_index = 0
pivot = _list(pivot_index)
left_list = [i fori in_list[:pivot_index] ifi < pivot]
right_list = [i fori in_list[pivot_index:] ifi > pivot]
returnquick_sort(left) + [pivot] + quick_sort(right)
选择排序
defselect_sort(seq):
n = len(seq)
fori inrange(n- 1)
min_idx = i
forj inrange(i+ 1,n):
ifseq[j] < seq[min_inx]:
min_idx = j
ifmin_idx != i:
seq[i], seq[min_idx] = seq[min_idx],seq[i]
插入排序
definsertion_sort(_list):
n = len(_list)
fori inrange( 1,n):
value = _list[i]
pos = i
whilepos > 0andvalue < _list[pos - 1]
_list[pos] = _list[pos - 1]
pos -= 1
_list[pos] = value
print(sql)
归并排序
defmerge_sorted_list(_list1,_list2):#合并有序列表
len_a, len_b = len(_list1),len(_list2)
a = b = 0
sort = []
whilelen_a > a andlen_b > b:
if_list1[a] > _list2[b]:
sort.append(_list2[b])
b += 1
else:
sort.append(_list1[a])
a += 1
iflen_a > a:
sort.append(_list1[a:])
iflen_b > b:
sort.append(_list2[b:])
returnsort
defmerge_sort(_list):
iflen(list1)< 2:
returnlist1
else:
mid = int(len(list1)/ 2)
left = mergesort(list1[:mid])
right = mergesort(list1[mid:])
returnmerge_sorted_list(left,right)
堆排序heapq模块
fromheapq importnsmallest
defheap_sort(_list):
returnnsmallest(len(_list),_list)
栈
fromcollections importdeque
classStack:
def__init__(self):
self.s = deque
defpeek(self):
p = self.pop
self.push(p)
returnp
defpush(self, el):
self.s.append(el)
defpop(self):
returnself.pop
队列
fromcollections importdeque
classQueue:
def__init__(self):
self.s = deque
defpush(self, el):
self.s.append(el)
defpop(self):
returnself.popleft
二分查找
defbinary_search(_list,num):
mid = len(_list)// 2
iflen(_list) < 1:
returnFlase
ifnum > _list[mid]:
BinarySearch(_list[mid:],num)
elifnum < _list[mid]:
BinarySearch(_list[:mid],num)
else:
return_list.index(num)

面试加强题:

关于数据库优化及设计

如何使用两个栈实现一个队列

反转链表

合并两个有序链表

删除链表节点

反转二叉树

设计短网址服务?62进制实现

设计一个秒杀系统(feed流)? https://www.jianshu.com/p/ea0259d109f9

为什么mysql数据库的主键使用自增的整数比较好?使用uuid可以吗?为什么?

如果InnoDB表的数据写入顺序能和B+树索引的叶子节点顺序一致的话,这时候存取效率是最高的。为了存储和查询性能应该使用自增长id做主键。

对于InnoDB的主索引,数据会按照主键进行排序,由于UUID的无序性,InnoDB会产生巨大的IO压力,此时不适合使用UUID做物理主键,可以把它作为逻辑主键,物理主键依然使用自增ID。为了全局的唯一性,应该用uuid做索引关联其他表或做外键

如果是分布式系统下我们怎么生成数据库的自增id呢?

使用redis

基于redis实现一个分布式锁,要求一个超时的参数

setnx

setnx + expire

如果redis单个节点宕机了,如何处理?还有其他业界的方案实现分布式锁码?

使用hash一致算法

缓存算法

LRU(least-recently-used):替换最近最少使用的对象

LFU(Least frequently used):最不经常使用,如果一个数据在最近一段时间内使用次数很少,那么在将来一段时间内被使用的可能性也很小

服务端性能优化方向

使用数据结构和算法

数据库

索引优化

慢查询消除

slow_query_log_file开启并且查询慢查询日志

通过explain排查索引问题

调整数据修改索引

批量操作,从而减少io操作

使用NoSQL:比如Redis

网络io

批量操作

pipeline

缓存

Redis

异步

Asyncio实现异步操作

使用Celery减少io阻塞

并发

多线程

Gevent