假如你和我一样在准备24年的春招,在前端全栈外,再准备一些AI的内容是非常有必要的。24年是AI红利年,AIGC+各种岗位大厂机会会多些,同意的请点赞。也欢迎朋友们加我微信shunwuyu, 一起交流。
前言
初五接财神,祝龙年,各位都拿下大厂offer。初五也是情人节,财神爷爱你。
准备春招,得先把全栈项目完善一下。怎么给面试官介绍自己的项目亮点和难点呢?完整的登录流程(JWT)算一个,精心设计的表结构和SQL优化比较有区分度。比如面试官(后端大佬)喜欢问项目有几张表,索引怎么建的?我们可以带着问题反向做项目开发,这样更容易面试官。
除此之外,我还打算安排上AIGC
的亮点。前段时间,接触了Text2SQL中的"茅台"Vanna, jser全栈做复杂SQL是道坎。有了Vanna, 复杂SQL查询有如神助,只需把需求表达,SQL直接生成,原地起飞... 面试官再也不用担心全栈能不能搞了。
数据表设计
数据库设计文件,我选用了xb2-node-assets/database at master · ninghao/xb2-node-assets (github.com)。在这里,我假设大家已经按照这个SQL文件,在本地mysql中建好了相应数据表、导入了初始数据。
现在大厂面试基本都用Boss直聘,有hc的部门老大负责招聘。老大可能是前端,也可能是后端。如果老大偏后端,看到我们简历里有全栈项目的时候,比较大概率会问个问题:"你的项目有几张表啊"?一针见血,倾刻了解我们的全栈能力,不浪费时间。所以我们要准备好,准备好后,刻意引导面试官问这个问题。
几张表?
我们的后端API项目是一个博客
系统。相比入门的博客系统,用户、文章、评论三张表,这里细致的多。
user表
我们将用户头像avartar、用户喜欢的文章user_like_post独立成表,就多了两张表。
开始给面试官整活了,avatar单独拆分成一张表有以下好处:
- 减少冗余和存储效率
用户表是最核心的表。如果每个用户记录中都直接存储头像文件的二进制内容或大文本地址,随着用户数量增加,会导致用户表急剧膨胀,降低查询性能。
- 可扩展性和灵活性
将头像单独存放,可以更方便地进行图片存储、处理和分发。例如,可以为头像创建多种缩略图版本,并且可以根据需要灵活调整图片存储路径、格式或 CDN 加速服务,而无需影响到核心用户信息表。
- 查询性能优化
在实际应用中,查询用户的其他信息(如用户名、邮箱、文章等)远比查询头像频率高。分离后,读取用户基本信息时不会因为加载大量的图像数据而拖慢查询速度。
- 数据一致性与事务管理
当头像信息独立存储时,对头像的操作(上传、删除、替换)可以在不影响用户主信息的情况下独立完成,简化了事务管理和并发控制逻辑。
- 表结构清晰度与维护性
单独的头像表有助于保持用户表结构的简洁和规范化,有利于未来系统维护和扩展,同时符合数据库设计中的"第三范式"原则,即每一张表只描述一件事情。name
采用了UNI唯一索引,用户名不可重复。
你看,这活整的不错。面试官想听的就是我们在设计表的时候,能不能查询到后期的查询,三大范式和性能优化等。能搞这些,就一定能做全栈。
user_like_post
关系型的mysql,可以通过这张表实现点赞、取消点赞功能。还可以根据这些信息进行数据分析,如统计最受欢迎的内容、内容推荐等
post表
文章表,和用户表一样,也是博客项目的核心主表。我们将文章中上传的文件单独成表file、文章打的tag表,也和user表的avatar有着异曲同工之妙。
- post表主要存储文章的基础信息
主要存储文章的基础信息,如id
(文章ID)、title
(标题)、content
(内容)、userId
(作者ID)等。便于查询、更新和展示单篇文章的所有基本信息。userId
我们用的是MUL索引。
MUL:表示非唯一索引(Multiple-Key Index),也称为普通索引或多列索引,它允许索引列中有重复的值。
arduino
CREATE INDEX idx_user_id ON post (userId);
我们只需要这样创建普通索引,不需要特别指定MUL。
Post表中为userId
字段使用MUL(非唯一)索引主要是出于查询优化和关联查询的需求.在Post表中的userId
字段设置MUL索引是为了优化常见的用户相关帖子查询以及多表关联查询的执行效率。
file表
file表和avatar差不多, 不赘述。
tag
所有的标签
post_tag
这里我们看到post_tag有两个字段,分别是postId和tagId。它和avatar、file不一样,前两者是一对多关系,而post_tag是多对多关系。
一个帖子(Post)可以有多个标签(Tag),同样,一个标签也可以关联到多个帖子
comment 表
评论表的parentI设计,实现了评论的评论。postId、userId、parentId三者都加了普通索引,分别适用于文章评论列表、用户评论列表、评论的评论列表的查询优化。
分析完后,我们可以就面试官"你的项目有几张表啊"这个问题,在索引、业务场景和性能优化上侃大山,足够了。
AIGC SQL生成
我在之前写了Vanna Text2SQL数据库平权 - 掘金 (juejin.cn)、Vanna数据平权:非技术人员的数据库自由 - 掘金 (juejin.cn)两篇文章,大家可以先看下Vanna的入门介绍再继续。
我们通过之前的一段代码,回顾一下:
python
# 安装vanna
!pip install vanna
# vanna.remote 提供访问远程的数据库,这个很实用
from vanna.remote import VannaDefault
# 返回vn 实例
vn = VannaDefault(model='chinook', api_key='****')
# 连接数据库
vn.connect_to_sqlite('https://vanna.ai/Chinook.sqlite')
# 销售额排名前十的艺术家是?
vn.ask('What are the top 10 artists by sales?')
# 执行
from vanna.flask import VannaFlaskApp
VannaFlaskApp(vn).run()
几个重点概念:
-
vanna为text2SQL 开发效率工具升级到产品级。VannaFlaskApp(Flask是python的框架)接收一个vn实例就可以运行起来sql的chatBot,体验很好。
-
vn实例需要model和api_key。
chinook
是Vanna推荐的LLM, 当然我们也可以切换成其它大模型。我们可以把chinook
看成对SQL生成微调优化过的模型。 -
vn实例上的connect_to_sqlite 方法,通过uri就连上了。我们的数据表会像LLM外的知识库一样,给LLM做RAG应用。
-
vn实例上的ask方法,让我们可以自然语义得到SQL。
所以现在我们需要去查看下文档mysql
怎么连接,其余几步都是一样的。
MYSQL 配置
Vanna对Sqlite、Postgres 提供了直接的方法,Mysql属于Vanna Docs: Connect to Other Databases里的other database。
现在文档还不太完善,经过一番摸索,试验成功。大家来打小抄哈。
ini
import pandas as pd
from vanna.remote import VannaDefault
# mysql驱动
import pymysql
# 返回vn 实例
vn = VannaDefault(model='chinook', api_key='81e56ab6fd2xxxxxx20e28444f3b45')
# 连接对象
conn = pymysql.connect(host='127.0.0.1',
port=3306,
user='root',
password='xxxxxx',
db='xb2',
charset='utf8mb4')
# You define a function that takes in a SQL query as a string and returns a pandas dataframe
def run_sql(sql: str) -> pd.DataFrame:
df = pd.read_sql_query(sql, conn)
return df
# This gives the package a function that it can use to run the SQL
vn.run_sql = run_sql
vn.run_sql_is_set = True
# 销售额排名前十的艺术家是?
vn.ask('how many post are there?')
# 执行
from vanna.flask import VannaFlaskApp
VannaFlaskApp(vn).run()
vanna运行起来了,我们问的问题也拿到了SQL,当然比较简单,等下尝试个比较复杂的。运行花了些时间,这里应该有embedding mysql xb2数据库,构建RAG的过程。
提出复杂问题, 得到SQL
- what are the top 10 post by user_like_post?
vanna目前还需要使用英文交流,我们提出根据用户点赞排名前10的文章。
返回的SQL是
vbnet
SELECT p.post_id, p.post_content, COUNT(*) AS like_count FROM post p JOIN user_like_post ulp ON p.post_id = ulp.post_id GROUP BY p.post_id, p.post_content ORDER BY like_count DESC LIMIT 10;
有点问题,稍微debug后,我们得出了可以使用的SQL。
css
SELECT p.id, p.content,p.title, COUNT(*) AS like_count
FROM post p
JOIN user_like_post ulp ON p.id = ulp.postId
GROUP BY p.id, p.title
ORDER BY like_count DESC
LIMIT 10;
感兴趣的同学,可以自己再玩玩, 要去亲戚家拜年了, 例子就先不给那么多, 下次在评论区里给。也欢迎大家一起来给。
总结
本文为春招做准备,优化了全栈项目中的数据表设计,而且在复杂SQL查询这块使用了SQL Copilot Vanna, 会让面试官眼前一亮。