Commit 9ff9250e authored by jackfrued's avatar jackfrued

更新了数据库和电商项目文档

parent 340b91b6
......@@ -12,16 +12,22 @@
### 需求要点
1. 用户端
- 首页(商品分类、广告轮播、滚动快讯、瀑布加载)
- 首页(商品分类、广告轮播、滚动快讯、瀑布加载、推荐、折扣、热销、……
- 用户(登录(第三方登录)、注册、注销、自服务(个人信息、浏览历史、收货地址、……))
- 商品(分类、列表、详情、搜索、添加到购物车
- 商品(分类、列表、详情、搜索、热门搜索、搜索历史、添加到购物车、收藏、关注、……
- 购物车(查看、编辑(修改数量、删除商品、清空))
- 订单(提交订单(支付)、历史订单、订单详情、订单评价)
- 订单(提交订单(支付)、历史订单、订单详情、订单评价、……
2. 管理端
- 核心业务实体的CRUD
- 定时任务(周期性和非周期性)
- 报表功能(Excel、PDF、ECharts)
- 权限控制(RBAC)
- 业务流转(Activity、Airflow、Spiff、自定义)
- 三方服务(地图、短信、物流、支付、实名认证、天气、监控、……)
> 提示:可以通过思维导图来进行需求的整理,思维导图上的每个叶子节点都是不可再拆分的功能。
> 提示:可以通过思维导图来进行需求的整理,思维导图上的每个叶子节点都是不可再拆分的功能,而且都是动词
### 物理模型设计
......@@ -103,6 +109,8 @@ INSTALLED_APPS = [
#### 查询缓存
自定义装饰器实现查询结果的缓存。
```Python
from pickle import dumps
from pickle import loads
......@@ -188,7 +196,7 @@ class ShoppingCart(object):
return total
```
已登录用户的购物车可以放在数据库中(可以先在Redis中缓存);未登录用户的购物车可以保存在Cookie中(减少服务器端内存开销)。
已登录用户的购物车可以放在数据库中(可以先在Redis中缓存);未登录用户的购物车可以保存在Cookie、localStorage或sessionStorage中(减少服务器端内存开销)。
```JSON
{
......@@ -309,19 +317,478 @@ if alipay.verify(params, params.pop('sign')):
1. 使用数据库的模糊查询功能 - 效率低,每次需要全表扫描,不支持分词。
2. 使用数据库的全文检索功能 - MySQL 5.6以前只适用于MyISAM引擎,检索操作和其他的DML操作耦合在数据库中,可能导致检索操作非常缓慢,数据量达到百万级性能显著下降,查询时间很长。
3. 使用开源搜索引擎 - 索引数据和原始数据分离,可以使用ElasticSearch或Solr来提供外置索引服务,如果不考虑高并发的全文检索需求,纯Python的Whoosh也可以考虑。ElasticSearch-Analysis-IK
3. 使用开源搜索引擎 - 索引数据和原始数据分离,可以使用ElasticSearch或Solr来提供外置索引服务,如果不考虑高并发的全文检索需求,纯Python的Whoosh也可以考虑。
#### ElasticSearch
ElasticSearch是一个高可扩展的开源全文搜索和分析引擎,它允许存储、搜索和分析大量的数据,并且这个过程是近实时的。它通常被用作底层引擎和技术,为复杂的搜索功能和要求提供动力,大家熟知的维基百科、Stack-Overflow、Github都使用了ElasticSearch。
ElasticSearch既是一个分布式文档数据库又是一个高可扩展的开源全文搜索和分析引擎,它允许存储、搜索和分析大量的数据,并且这个过程是近实时的。它通常被用作底层引擎和技术,为复杂的搜索功能和要求提供动力,大家熟知的维基百科、Stack-Overflow、Github都使用了ElasticSearch。
ElasticSearch的底层是开源搜索引擎[Lucene](https://lucene.apache.org/)。但是直接用Lucene会非常麻烦,必须自己编写代码去调用它的接口而且只支持Java语言。ElasticSearch相当于是对Lucene进行了封装,提供了REST API的操作接口。搜索引擎在对数据构建索引时,需要进行分词处理。ElasticSearch不支持基于中文分词的索引,需要配合扩展elasticsearch-analysis-ik来实现中文分词处理
ElasticSearch的底层是开源搜索引擎[Lucene](https://lucene.apache.org/),但是直接用Lucene会非常麻烦,必须自己编写代码去调用它的接口而且只支持Java语言。ElasticSearch相当于对Lucene进行了一次全面的封装,提供了REST风格的API接口,通过基于HTTP协议的访问方式屏蔽了编程语言的差异。ElasticSearch会为数据构建[倒排索引](https://zh.wikipedia.org/zh-hans/%E5%80%92%E6%8E%92%E7%B4%A2%E5%BC%95),但是ElasticSearch内置的分词器对中文分词的支持几乎为零,因此需要通过安装elasticsearch-analysis-ik插件来提供中文分词服务
ElasticSearch的安装和配置可以参考[《ElasticSearch之Docker安装》](https://blog.csdn.net/jinyidong/article/details/80475320)。除了ElasticSearch之外,也可以使用Solr、Whoosh等来提供搜索引擎服务,基本上Django项目中可以考虑如下两套方案:
- Haystack(django-haystack / drf-haystack) + Whoosh + Jieba
- haystack(django-haystack / drf-haystack) + whoosh + Jieba
- haystack (django-haystack / drf-haystack)+ elasticsearch
####安装和使用ElasticSearch
1. 使用Docker安装ElasticSearch。
```Shell
docker pull elasticsearch:6.5.3
docker run -d -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms512m -Xmx512m" --name es elasticsearch:6.5.3
```
> 说明:上面创建容器时通过`-e`参数指定了使用单机模式和Java虚拟机最小最大可用堆空间的大小,堆空间大小可以根据服务器实际能够提供给ElasticSearch的内存大小来决定,默认为2G。
2. 创建数据库。
请求:PUT - `http://1.2.3.4:9200/demo`
响应:
```JSON
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "demo"
}
```
3. 查看创建的数据库。
请求:GET - `http://1.2.3.4:9200/demo`
响应:
```JSON
{
"demo": {
"aliases": {},
"mappings": {},
"settings": {
"index": {
"creation_date": "1552213970199",
"number_of_shards": "5",
"number_of_replicas": "1",
"uuid": "ny3rCn10SAmCsqW6xPP1gw",
"version": {
"created": "6050399"
},
"provided_name": "demo"
}
}
}
}
```
4. 插入数据。
请求:POST - `http://1.2.3.4:9200/demo/goods/1/`
请求头:Content-Type: application/json
参数:
```JSON
{
"no": "5089253",
"title": "Apple iPhone X (A1865) 64GB 深空灰色 移动联通电信4G手机",
"brand": "Apple",
"name": "Apple iPhone X",
"product": "中国大陆",
"resolution": "2436 x 1125",
"intro": "一直以来,Apple都心存一个设想,期待能够打造出这样一部iPhone:它有整面屏幕,能让你在使用时,完全沉浸其中,仿佛忘了它的存在。它是如此智能,哪怕轻轻一瞥,都能得到它心有灵犀的回应。而这个设想,终于随着iPhone X的到来成为了现实。现在,就跟未来见个面吧。"
}
```
响应:
```JSON
{
"_index": "demo",
"_type": "goods",
"_id": "1",
"_version": 4,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 3,
"_primary_term": 1
}
```
5. 删除数据。
请求:DELETE - `http://1.2.3.4:9200/demo/goods/1/`
响应:
```JSON
{
"_index": "demo",
"_type": "goods",
"_id": "1",
"_version": 2,
"result": "deleted",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 1,
"_primary_term": 1
}
```
6. 更新数据。
请求:PUT - `http://1.2.3.4:9200/demo/goods/1/_update`
请求头:Content-Type: application/json
参数:
```JSON
{
"doc": {
"no": "5089253",
"title": "Apple iPhone X (A1865) 64GB 深空灰色 移动联通电信4G手机",
"brand": "Apple(苹果)",
"name": "Apple iPhone X",
"product": "美国",
"resolution": "2436 x 1125",
"intro": "一直以来,Apple都心存一个设想,期待能够打造出这样一部iPhone:它有整面屏幕,能让你在使用时,完全沉浸其中,仿佛忘了它的存在。它是如此智能,哪怕轻轻一瞥,都能得到它心有灵犀的回应。而这个设想,终于随着iPhone X的到来成为了现实。现在,就跟未来见个面吧。"
}
}
```
响应:
```JSON
{
"_index": "demo",
"_type": "goods",
"_id": "1",
"_version": 10,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 9,
"_primary_term": 1
}
```
7. 查询数据。
请求:GET - `http://1.2.3.4:9200/demo/goods/1/`
响应:
```JSON
{
"_index": "demo",
"_type": "goods",
"_id": "1",
"_version": 10,
"found": true,
"_source": {
"doc": {
"no": "5089253",
"title": "Apple iPhone X (A1865) 64GB 深空灰色 移动联通电信4G手机",
"brand": "Apple(苹果)",
"name": "Apple iPhone X",
"product": "美国",
"resolution": "2436 x 1125",
"intro": "一直以来,Apple都心存一个设想,期待能够打造出这样一部iPhone:它有整面屏幕,能让你在使用时,完全沉浸其中,仿佛忘了它的存在。它是如此智能,哪怕轻轻一瞥,都能得到它心有灵犀的回应。而这个设想,终于随着iPhone X的到来成为了现实。现在,就跟未来见个面吧。"
}
}
}
```
#### 配置中文分词和拼音插件
1. 进入Docker容器的plugins目录。
```Shell
docker exec -it es /bin/bash
```
2. 下载和ElasticSearch版本对应的[ik](https://github.com/medcl/elasticsearch-analysis-ik)和[pinyin](https://github.com/medcl/elasticsearch-analysis-pinyin)插件。
```Shell
cd plugins/
mkdir ik
cd ik
wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.5.3/elasticsearch-analysis-ik-6.5.3.zip
unzip elasticsearch-analysis-ik-6.5.3.zip
rm -f elasticsearch-analysis-ik-6.5.3.zip
cd ..
mkdir pinyin
cd pinyin
wget https://github.com/medcl/elasticsearch-analysis-pinyin/releases/download/v6.5.3/elasticsearch-analysis-pinyin-6.5.3.zip
unzip elasticsearch-analysis-pinyin-6.5.3.zip
rm -f elasticsearch-analysis-pinyin-6.5.3.zip
```
3. 退出容器,重启ElasticSearch。
```Shell
docker restart es
```
4. 测试中文分词效果。
请求:POST - `http://1.2.3.4:9200/_analyze`
请求头:Content-Type: application/json
参数:
```JSON
{
"analyzer": "ik_smart",
"text": "中国男足在2022年卡塔尔世界杯预选赛中勇夺小组最后一名"
}
```
响应:
```JSON
{
"tokens": [
{
"token": "中国",
"start_offset": 0,
"end_offset": 2,
"type": "CN_WORD",
"position": 0
},
{
"token": "男足",
"start_offset": 2,
"end_offset": 4,
"type": "CN_WORD",
"position": 1
},
{
"token": "在",
"start_offset": 4,
"end_offset": 5,
"type": "CN_CHAR",
"position": 2
},
{
"token": "2022年",
"start_offset": 5,
"end_offset": 10,
"type": "TYPE_CQUAN",
"position": 3
},
{
"token": "卡塔尔",
"start_offset": 10,
"end_offset": 13,
"type": "CN_WORD",
"position": 4
},
{
"token": "世界杯",
"start_offset": 13,
"end_offset": 16,
"type": "CN_WORD",
"position": 5
},
{
"token": "预选赛",
"start_offset": 16,
"end_offset": 19,
"type": "CN_WORD",
"position": 6
},
{
"token": "中",
"start_offset": 19,
"end_offset": 20,
"type": "CN_CHAR",
"position": 7
},
{
"token": "勇夺",
"start_offset": 20,
"end_offset": 22,
"type": "CN_WORD",
"position": 8
},
{
"token": "小组",
"start_offset": 22,
"end_offset": 24,
"type": "CN_WORD",
"position": 9
},
{
"token": "最后",
"start_offset": 24,
"end_offset": 26,
"type": "CN_WORD",
"position": 10
},
{
"token": "一名",
"start_offset": 26,
"end_offset": 28,
"type": "CN_WORD",
"position": 11
}
]
}
```
5. 测试拼音分词效果。
请求:POST - `http://1.2.3.4:9200/_analyze`
请求头:Content-Type: application/json
参数:
```JSON
```
响应:
```JSON
{
"tokens": [
{
"token": "zhang",
"start_offset": 0,
"end_offset": 0,
"type": "word",
"position": 0
},
{
"token": "zxy",
"start_offset": 0,
"end_offset": 0,
"type": "word",
"position": 0
},
{
"token": "xue",
"start_offset": 0,
"end_offset": 0,
"type": "word",
"position": 1
},
{
"token": "you",
"start_offset": 0,
"end_offset": 0,
"type": "word",
"position": 2
}
]
}
```
#### 全文检索功能
可以通过GET或者POST请求进行搜索,下面演示了搜索有“未来”关键词商品。
1. GET - `http://120.77.222.217:9200/demo/goods/_search?q=未来`
> 注意:URL中的中文应该要处理成百分号编码。
```JSON
{
"took": 19,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 0.73975396,
"hits": [
{
"_index": "demo",
"_type": "goods",
"_id": "1",
"_score": 0.73975396,
"_source": {
"doc": {
"no": "5089253",
"title": "Apple iPhone X (A1865) 64GB 深空灰色 移动联通电信4G手机",
"brand": "Apple(苹果)",
"name": "Apple iPhone X",
"product": "美国",
"resolution": "2436*1125",
"intro": "一直以来,Apple都心存一个设想,期待能够打造出这样一部iPhone:它有整面屏幕,能让你在使用时,完全沉浸其中,仿佛忘了它的存在。它是如此智能,哪怕轻轻一瞥,都能得到它心有灵犀的回应。而这个设想,终于随着iPhone X的到来成为了现实。现在,就跟未来见个面吧。"
}
}
},
{
"_index": "demo",
"_type": "goods",
"_id": "3",
"_score": 0.68324494,
"_source": {
"no": "42417956432",
"title": "小米9 透明尊享版 手机 透明尊享 全网通(12GB + 256GB)",
"brand": "小米(MI)",
"name": "小米(MI)小米9透明",
"product": "中国大陆",
"resolution": "2340*1080",
"intro": "全面透明机身,独特科幻机甲风,来自未来的设计。"
}
}
]
}
}
```
URL中可用的搜索参数如下表所示:
| 参数 | 说明 |
| ---------------- | ------------------------------------------------- |
| q | 查询字符串 |
| analyzer | 分析查询字符串使用的分词器 |
| analyze_wildcard | 通配符或者前缀查询是否被分析,默认为false |
| default_operator | 多个条件之间的关系,默认为OR,可以修改为AND |
| explain | 在返回的结果中包含评分机制的解释 |
| fields | 只返回索引中指定的列,多个列中间用逗号隔开 |
| sort | 排序参考的字段,可以用:asc和:desc来指定升序和降序 |
| timeout | 超时时间 |
| from | 匹配结果的开始值,默认为0 |
| size | 匹配结果的条数,默认为10 |
2. POST - `http://120.77.222.217:9200/demo/goods/_search`
请求头:Content-Type: application/json
参数:
```JSON
```
- Haystack (django-haystack / drf-haystack)+ ElasticSearch + ElasticSearch-Analysis-IK
响应:
```JSON
```
#### Django对接ElasticSearch
......@@ -343,12 +810,11 @@ INSTALLED_APPS = [
HAYSTACK_CONNECTIONS = {
'default': {
# 引擎配置
'ENGINE':
'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine',
'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine',
# 搜索引擎服务的URL
'URL': 'http://...',
'URL': 'http://1.2.3.4:9200',
# 索引库的名称
'INDEX_NAME': '...',
'INDEX_NAME': 'goods',
},
}
......@@ -362,22 +828,21 @@ HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
from haystack import indexes
class HouseInfo(indexes.SearchIndex, indexes.Indexable):
class GoodsIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
def get_model(self):
return HouseInfo
return Goods
def index_queryset(self, using=None):
return self.get_model().objects.all()
```
编辑text字段的模板(需要放在templates/search/indexes/rent/houseinfo_text.txt):
编辑text字段的模板(需要放在templates/search/indexes/demo/goods_text.txt):
```
{{object.title}}
{{object.detail}}
{{object.intro}}
```
配置URL:
......@@ -395,4 +860,5 @@ urlpatterns = [
python manage.py rebuild_index
```
> 说明:可以参考[《Django Haystack 全文检索与关键词高亮》](https://www.zmrenwu.com/post/45/)一文来更深入的了解基于Haystack的全文检索操作。
\ No newline at end of file
> 说明:可以参考[《Django Haystack 全文检索与关键词高亮》](https://www.zmrenwu.com/post/45/)一文来更深入的了解基于Haystack的全文检索操作。
## MySQL相关知识
### 存储引擎
1. InnoDB
2. MyISAM
### 数据类型
### 索引
#### 索引的类型
1. B-Tree索引
2. HASH索引
3. R-Tree索引(空间索引)
4. Full-text索引(全文索引)
### 视图
查询的快照,可以将访问权限控制到列上。
```SQL
create view ... as select ...
drop view ...
```
### 存储过程
```SQL
create procedure ... (params)
begin
...
end;
call ...
```
```Python
cursor.callproc('...')
```
### 触发器
不能用,因为多个行锁可能直接升级为表锁,导致性能低下。
### 事务控制
### SQL注入攻击
### 数据分区
### SQL优化
#### 优化步骤
1. 通过`show status`了解各种SQL的执行频率。
```SQL
show status like 'com_%';
show status like 'innodb_%';
show status like 'connections';
show status like 'slow_queries';
```
2. 定位低效率的SQL语句 - 慢查询日志。
```SQL
show processlist
```
3. 通过`explain`了解SQL的执行计划。
- select_type:查询类型(simple、primary、union、subquery)
- table:输出结果集的表
- type:访问类型(ALL、index、range、ref、eq_ref、const、NULL)
- possible_keys:查询时可能用到的索引
- key:实际使用的索引
- key_len:索引字段的长度
- rows:扫描的行数
- extra:额外信息
4. 通过`show profiles``show profile for query`分析SQL。
#### SQL优化
1. 优化insert语句
2. 优化order by语句
3. 优化group by语句
4. 优化嵌套查询
5. 优化or条件
6. 优化分页查询
7. 使用SQL提示
- USE INDEX
- IGNORE INDEX
- FORCE INDEX
#### 配置优化
1. 调整max_connections
2. 调整back_log
3. 调整table_open_cache
4. 调整thread_cache_size
5. 调整innodb_lock_wait_timeout
#### 架构优化
1. 通过拆分提高表的访问效率
- 垂直拆分
- 水平拆分
2. 逆范式理论
- 数据表设计的规范程度称之为范式(Normal Form)
- 1NF:列不能再拆分
- 2NF:所有的属性都依赖于主键
- 3NF:所有的属性都直接依赖于主键(消除传递依赖)
- BCNF:消除非平凡多值依赖
3. 使用中间表提高统计查询速度
### 数据备份
#### 导入和导出
1. select ... into outfile ...
2. load data infile ... into table ...
3. mysqldump
4. mysqlimport
#### ibbackup工具
#### xtrabackup工具
### 主从复制
### 集群
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment