Shawn's Blog

一个伪程序员的伪技术博客

0X00 前言

不论多初级的后端程序员,只要认可自己是“后端程序员”那最起码也是听过“数据库索引”这个东西的,应该也直到这东西能让数据库变快。但是具体“数据库索引”是个什么东西,怎么用,为什么能让数据库变快可能就不一定清楚了。

这篇博客仅仅是简述了“数据库索引”的最基础内容,不涉及内部原理(其实我也还没搞懂)。阅读了本篇博客可以(也许)搞清楚怎么给一张表添加索引,索引加在哪儿,以及为什么不能给所有字段加索引。

0X01 一个业务场景

假设我们搞了一个电商平台“并夕夕”,现在有超多用户大概几百万,很多人都在我们系统里买了东西,大概下了1000W单。那么我们用来存储订单的表就有大概1000W条数据了,那么我们这个没有进行过任何优化的数据库就已经顶不住了,我们每次在后台查看订单列表的时候一个查询就要快20s,显然是一个接受不了的速度了。

那么我们来看一下这个列表都干了什么:“根据 订单状态(下单待支付/已支付/配送中/已收货/退货中/已完成),订单类型(直接购买/拼单购买/分享白拿)等状态筛选,并取出前20条展示出来”。后台SQL是这个样子的SELECT * FROM bxx_order WHERE order_status = xxx AND order_type = xxx ORDER BY -id LIMIT 20,我们可以看到真正会影响性能的主要就在WHERE子句里的查询条件。接下来我们给这两个字段分别加上索引,查询效率就会高非常非常多。

阅读全文 »

0X00 给一个方法计时

现在我们有一个需求,需要给程序中的一部分方法计时,以监控他们执行完具体用了多久。那么在没有装饰器的情况下我们会写出类似这样的代码:

1
2
3
4
5
6
7
8
9
10
import datetime

def foo():
pass # some code


start = datetime.datetime.now()
foo()
end = datetime.datetime.now()
print((end - start).seconds)

0X01 引入装饰器

如果只是临时给一个方法使用也不是不行,但是如果我们需要监控大量的方法呢?众所周知Python中function也是可以作为参数传递的,那来看一下下面这种写法呢

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import datetime


def timer(func):
def run_func(): # 方法内部将之前计时的功能封装起来
start = datetime.datetime.now()
result = func() # 得到参数方法的返回值
end = datetime.datetime.now()
print((end - start).seconds)
return result # 将真正的结果返回给调用者

return run_func # 调用内部方法,进行计时


def foo():
pass # some code


def bar():
pass # some code


# 将方法作为参数发送给 timer()
timer(foo)()
timer(bar)()

因为上面timer(foo)返回的结果是一个func,所以后面需要再加一对括号来调用这个方法

这种方法只写了一次计时的逻辑,但是可以给任意一个方法使用,其实这时候def timer(func)已经是装饰器了,下面调用的方法timer(foo)/timer(bar)也是正确的装饰器使用方法。那是不是觉得和常见的装饰器使用不太一样呢?其实常见的@timer用法是Python中提供的一种语法糖。

阅读全文 »

0X00 什么是可迭代对象

我们平时用到的list/set/tuples是最常见的可迭代对象,简单判断就是说当可以for item in this_obj的时候this_obj就是可迭代对象。所以不只是list/set/tuples,打开的文件或是Django中的queryset也都是可迭代对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
In [1]: user_list = iter(['shawn', 'danny', 'jenny', 'liming'])

In [2]: next(user_list)
Out[2]: 'shawn'

In [3]: next(user_list)
Out[3]: 'danny'

In [4]: next(user_list)
Out[4]: 'jenny'

In [5]: next(user_list)
Out[5]: 'liming'

使用iter()可以将列表变为一个迭代器,然后使用next方法访问下一个元素。实际上iter(this_obj)方法和next(this_obj)方法分别调用的是this_obj.__iter__()this_obj.__next__(),所以我们如果想要自己实现迭代器的话就需要实现这两个方法。

阅读全文 »

0X00 前言

没有什么前言,只有一个数据库模型,下面的代码使用这个模型拿来测试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from django.db import models


class Major(models.Model):
name = models.CharField(
'名字',
max_length=100,
blank=True,
null=True,
)


class Student(models.Model):
name = models.CharField(
'名字',
max_length=100,
blank=True,
null=True,
)
select_major = models.ForeignKey(
Major,
verbose_name='专业',
on_delete=models.SET_NULL,
blank=True,
null=True,
related_name='main_student',
)
ext_major = models.ManyToManyField(
Major,
verbose_name='附加专业',
related_name='ext_student',
)

我们先假设Major表存在10条数据,而Student表存在1万条数据。

阅读全文 »

0X00 没有什么用的开头

众所周知https是安全加密的协议,那么https究竟是如何保证数据传输的安全性的呢?这里来简单介绍一下https的安全机制。

0X01 简介

HTTPS全称是 Hypertext Transfer Protocol Secure 也就是传统的HTTP加上了S Secure,也可以叫 HTTP over TLS,总之就是加了密的HTTP嘛。

最常见的加密就是通信双方共有一个密钥,使用这个密钥对原文进行加密和解密,简单粗暴。但是万一密钥泄露了,那么任何人都可以用这个密钥解密你们通信的所有内容,甚至通信双方都是无感知的。(想象一下你和小姐姐的聊天记录被一个扣脚大汉一行行的看完还嘿嘿傻笑是不是贼恐怖)

这种加密方式有一个严肃的问题就在于通信双方得有一个约定密钥的机会,还要保证传输密钥的信道是绝对安全的。(想象一下你想跟小姐姐聊天的话需要先私下悄悄碰面,然后再一个没有人的地方悄咪咪的交换密钥,然后再用这个密钥进行加密通信)这还不是重点,重点就是你俩明明已经有了一个可以保证绝对安全的通信方法(在没有人的地方悄咪咪地通信)了,那为啥还非要交换密码然后加密通信呢,是不是觉得贼蠢。

HTTPS就能解决这种问题,下面我们来开始吧。我们假设一个场景就是客户端(你)和一台web服务器(小姐姐)通信的场景,在这个场景下描述HTTPS。

0X02 HTTPS的前提条件

HTTPS通信有两个重要前提条件,没有这些条件的话HTTPS是没有实际作用的

  1. 使用非对称加密算法对内容进行加密,目前我们使用的RSA算法就是非对称加密算法
  2. 存在一个绝对安全的第三方机构,我们称之为CA(Certificate Authority),我们认为它不会被攻击,他发布的信息都是可靠的

非对称加密:与对称加密的一个密钥用来加密解密不同,非对称加密有一对密钥,分为“公钥”和“私钥”。使用密钥对中的公钥对原文进行加密之后再次使用公钥解密是行不通的,必须使用对应的私钥才能对密文进行解密;

CA:CA是一个被认为绝对安全且诚实的第三方机构,服务器将自己密钥对中的公钥交由CA管理。客户端访问服务器时候可以从CA处取得服务器的公钥;

阅读全文 »
0%