在这篇文章中,我们将带领您了解MySQL的递归的全貌,包括树父子类别的相关情况。同时,我们还将为您介绍有关C语言函数的递归(上)、day05Mysql:pymysql的使用(前端+flask+pymy
在这篇文章中,我们将带领您了解MySQL的递归的全貌,包括树父子类别的相关情况。同时,我们还将为您介绍有关C语言函数的递归(上)、day05 Mysql: pymysql的使用 (前端+flask+pymysql的使用) mysql索引 解释执行 慢日志 分页性能方案、List 递归循环查询所有的 子类别、子子类别、子子子类别…………递归、MySQL 5.7 对未知级别的层次结构数据的递归查询的知识,以帮助您更好地理解这个主题。
本文目录一览:
MySQL的递归(树)父子类别(mysql递归查询父子)
我是mysql的新手。这是我的桌子:
类别表:
id | name | prent----------------------------1 | os | null2 | linux | 13 | ubuntu | 24 | xubuntu | 35 | lubuntu | 36 | zubuntu | 37 | zubuntu 2 | 68 | suse | 29 | fedora | 210 | windowse | 111 | windowse xp | 1012 | windowse 7 | 1013 | windowse 8 | 1014 | food | null15 | dance | null
每个类别都有一个父项,我想准备它们以显示在下拉菜单中。
这就是我想要得到的:
id | name | depth----------------------------1 | os | 02 | -linux | 13 | --ubuntu | 24 | ---xubuntu | 35 | ---lubuntu | 36 | ---zubuntu | 37 | ----zubuntu 2 | 48 | --suse | 29 | --fedora | 210 | -windows | 111 | --windows xp | 212 | --windows 7 | 213 | --windows 8 | 214 | food | 015 | dance | 0
在这里,类别没有顺序,我的代码必须为远离父母的孩子类别提供顺序。根据每个类别的父母的深度提供姓名前的缩进。每个类别的孩子数没有限制,但是类别总数不超过100。
有没有查询可以给出这样的结果?我更喜欢可以在PHP框架中以活动记录形式运行的查询。
答案1
小编典典 这个 主题
带给我。感谢@RolandoMySQLDBA
DELIMITER $$DROP FUNCTION IF EXISTS `GetAncestry` $$CREATE FUNCTION `GetAncestry` (GivenID INT) RETURNS VARCHAR(1024)DETERMINISTICBEGIN DECLARE rv VARCHAR(1024); DECLARE cm CHAR(1); DECLARE ch INT; SET rv = ''''; SET cm = ''''; SET ch = GivenID; WHILE ch > 0 DO SELECT IFNULL(`prent`,-1) INTO ch FROM (SELECT `prent` FROM Table1 WHERE id = ch) A; IF ch > 0 THEN SET rv = CONCAT(rv,cm,ch); SET cm = '',''; END IF; END WHILE; RETURN rv;END $$DELIMITER ;
在这里工作的 小提琴 。
SELECT id,GetAncestry(id) as parents from Table1 where id = 7;ID PARENTS7 6,3,2,1

C语言函数的递归(上)
函数递归:
一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法。
递归的主要思考方式:
把大事化小。
用递归的方法是实现:接受一个整型值(无符号),按照顺序打印它的每一位。 例如: 输入:1234,输出 1 2 3 4
void print(int n)
{
if (n > 9)
{
print(n / 10);
}
printf("%d ", n%10);
}
int main()
{
unsigned int num = 0;
scanf("%d", &num);
print(num);
return 0;
}
编写函数不允许创建临时变量,求字符串的长度。
//递归的方法
int my_strlen(char* str)
{
if (*str != ''\0'')
return 1 + my_strlen(str + 1);
else
return 0;
}
//把大事化小
//my_strlen("bit");
//1+my_strlen("it");
//1+1+my_strlen("t");
//1+1+1+my_strlen("")
//1+1+1+0
//3
int main()
{
char arr[] = "bit";
//模拟实现一个strlen函数
int len = my_strlen(arr);//arr是数组,数组传参,传过去的不是整个数组,而是第一个元素的地址
printf("%d\n", len);
return 0;
}
递归存在限制条件:
存在限制条件,当满足这个限制条件的时候,递归便不再继续。
每次递归调用之后越来越接近这个限制条件。
2021.1.24

day05 Mysql: pymysql的使用 (前端+flask+pymysql的使用) mysql索引 解释执行 慢日志 分页性能方案
day05 Mysql: pymysql的使用 (前端+flask+pymysql的使用) mysql索引 解释执行 慢日志 分页性能方案
一.pymysql的操作
commit(): 在数据库里增删改的时候,必须要进行提交,否则插入的数据不生效
1.增, 删, 改
#coding=utf-8
#Version:python3.5.0
#Tools:Pycharm 2017.3.2
__date__ = ''2019/12/12 13:37''
__author__ = ''wt''
import pymysql
username = input(''请输入用户名: '')
pwd = input(''请输入密码: '')
conn = pymysql.connect(host=''127.0.0.1'',
user=''root'',
password="",
database=''db2'',
port=3306,
charset=''utf8'',)
cur = conn.cursor()
sql = ''insert into userinfo(name,password) values(%s,%s)''
print(sql)
rst = cur.execute(sql,[username,pwd])
print(rst)
conn.commit() #增 删 改一定要记得提交到服务器
cur.close()
conn.close()
if rst:
print(''登录成功'')
else:
print(''登录失败'')
2.查 fetchone() fetchmany() fetchall() (fetch 取回)
#coding=utf-8
#Version:python3.5.0
#Tools:Pycharm 2017.3.2
__date__ = ''2019/12/12 13:37''
__author__ = ''wt''
import pymysql
conn = pymysql.connect(host=''127.0.0.1'',
user=''root'',
password="",
database=''db2'',
port=3306,
charset=''utf8'',)
# cur = conn.cursor()
cur = conn.cursor(cursor=pymysql.cursors.DictCursor) #可以把下面fetch查出的结果变成字典
sql = ''select * from userinfo''
print(sql)
rst = cur.execute(sql) #执行查询语句后, 查看记录的数据
print(rst)
print(cur.fetchone()) #查一条 默认结果是元组 #想要字典的形式,创建游标的时候设置参数即可
print(cur.fetchone()) #查下一条 若没有了, 返回None
print(cur.fetchmany(1)) #查多个,元组里面套元组, 当超过个数就是获取所有
print(cur.fetchall()) #获取所有
#看完了, 我想回去看? 移动光标(是行指针)
cur.scroll(-3,mode=''relative'') #相对移动,正值向前移动,负值向后移动
print(cur.fetchone())
cur.scroll(4,mode=''absolute'') #绝对移动,绝对于起始位置,正值是开始向前移动,负值报错
print(cur.fetchone())
cur.close()
conn.close()
if rst:
print(''登录成功'')
else:
print(''登录失败'')
二.前端 + flask + pymysql的使用
server.py
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2019/12/5
import json
import pymysql
from flask import Flask
from flask import request
from flask import Response
# 建立mysql连接
conn = pymysql.connect(
host=''localhost'',
user=''root'',
password="",
database=''db2'',
port=3306,
charset=''utf8''
)
#创建游标
cur = conn.cursor(cursor=pymysql.cursors.DictCursor)
#创建实例化请求对象
app = Flask(__name__)
# 定义路由
@app.route("/")
# 路由对应的函数处理
def index():
# 响应数据
resp = Response("<h2>首页</h2>")
# 允许所有跨域访问
resp.headers["Access-Control-Allow-Origin"] = "*"
return resp
# MTV 数据模板视图
@app.route("/course")
def courses():
sql = ''SELECT * FROM userinfo''
cur.execute(sql)
results = cur.fetchall()
# 返回json序列化的数据
resp = Response(json.dumps({
"msg": results
}))
resp.headers["Access-Control-Allow-Origin"] = "*"
return resp
# 前端发送post请求
# 定义路由
@app.route("/create", methods=["post", ])
def create():
print(request.form.get(''name''))
# 读取user.json中的原始的数据
with open("user.json", "r") as f:
# 将数据反序列化
data = json.loads(f.read())
# 将新数据添加到原始的数据中
data.append({"name": request.form.get(''name'')})
# 将此时最新的数据再次写入文件中
with open("user.json", "w") as f:
f.write(json.dumps(data))
# 再次返回最新的数据 响应回前端
resp = Response(json.dumps(data))
resp.headers["Access-Control-Allow-Origin"] = "*"
return resp
if __name__ == ''__main__'':
app.run(host="localhost", port=8800, )
index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div>
<input type="text" name="user">
<input type="button" value="提交">
<table>
<tr>
<td>id</td>
<td>name</td>
<td>pwd</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</table>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"></script>
<script>
$.ajax({
url:''http://localhost:8800/course'',
type:''get'',
dataType:''json'',
success:function (data) {
console.log(data.msg);
data.msg.forEach(function (ele,index) {
console.log(ele.id,ele.name,ele.password)
//未完待续
});
},
error:function () {
}
});
$(''input[type=button]'').click(function () {
$.ajax({
url:"http://127.0.0.1:8800/create",
type:''post'',
data:{
name:$(''input[type=text]'').val()
},
success:function (data) {
console.log(data);
}
})
})
</script>
</body>
</html>
user.json
[{"name": "wukong"}, {"name": "bajie"}, {"name": "zabbix"}, {"name": "zabbix"}]
三.mysql的索引
1.索引的介绍:
1).针对大量数据
数据库中专门用于帮助用户快速查找数据的一种数据结构,类似于字典中的目录,查找字典内容时可根据目录查找到数据的存放位置,然后直接获取
2).索引的作用:
3).常见的几种索引
普通索引
唯一索引
主键索引
组合索引(联合索引)
组合主键索引
组合唯一索引
组合普通索引
4).索引的分类:
hash索引:查询单条快,范围查找慢
btree索引: b+树,层数越多,数据量指数越增长(我们就用它,因为innodb默认支持它)
2.准备大表,插入百万数据
#创建索引测试表
drop table if exists big_data;
create table big_data(
id int primary key not null auto_increment,
name varchar(16) default null,
age int(11),
email varchar(64) default null
)engine=myisam default charset=utf8; #注意myisam存储引擎不产生引擎事务,数据插入速度极快, 为方便快速插入千万条测试数据,等我们插完数据,再把存储类型修改为innodb
#创建存储过程, 插入数据
delimiter $$ #声明存储过程的结束符号为$$ (delimiter 分隔符)
create procedure `insert_data_p`(num int) #(procedure 程序)
begin
declare n int default 1; #(declare 声明)
while n <= num do
insert into big_data(name,age,email) values(concat(''bajie'',n),rand()*50,concat(''bajie'',n,''@163.com''));
set n=n+1;
end while;
END$$ #$$结束
delimiter ; #重新声明分号为结束符号
#调用存储过程,插入500万条数据
call insert_data_p(5000000); #(105.28 sec)
#查看存储过程
show create procedure insert_data_p\G
#修改回我们的InnoDB
alter table big_data engine=innodb; #(21.91sec)
3.没有索引时,测试查询
mysql> select * from big_data where name = ''bajie1111111'';
+---------+--------------+------+----------------------+
| id | name | age | email |
+---------+--------------+------+----------------------+
| 1111111 | bajie1111111 | 41 | bajie1111111@163.com |
+---------+--------------+------+----------------------+
1 row in set (1.71 sec)
mysql> select * from big_data where email = ''bajie2222222@163.com'';
+---------+--------------+------+----------------------+
| id | name | age | email |
+---------+--------------+------+----------------------+
| 2222222 | bajie2222222 | 47 | bajie2222222@163.com |
+---------+--------------+------+----------------------+
1 row in set (1.77 sec)
4.创建索引(给某个字段创建索引)
1).普通索引
index:
作用: 仅有一个加速查询
创建索引:
创建表时,指定索引字段
create table t1(
id int not null auto_increment primary key,
name varchar(32) not null,
email varchar(64) not null,
index ix_name(name)
);
给已有表,创建索引字段
create index ix_name on big_data(name); #affected (25.93 sec)
有索引时,测试查询
mysql> select * from big_data where name = ''bajie1111111''; #有索引的字段查询快
+---------+--------------+------+----------------------+
| id | name | age | email |
+---------+--------------+------+----------------------+
| 1111111 | bajie1111111 | 41 | bajie1111111@163.com |
+---------+--------------+------+----------------------+
1 row in set (0.00 sec)
mysql> select * from big_data where email = ''bajie2222222@163.com''; #无索引的字段查询慢
+---------+--------------+------+----------------------+
| id | name | age | email |
+---------+--------------+------+----------------------+
| 2222222 | bajie2222222 | 47 | bajie2222222@163.com |
+---------+--------------+------+----------------------+
1 row in set (1.77 sec)
删除索引
drop index ix_name on big_data;
查看索引
show index from big_data;
2).主键索引
primary key:
把主键看成索引进行查询,速度快
主键的创建:
创建表的时候加的主键, 就等同于主键索引
create table t1(
id int not null auto_increment,
name varchar(32) not null,
email varchar(64) not null,
primary key(id)
);
创建表后, 加主键索引
alter table big_data add primary key(name);
删除主键
> alter table department drop primary key;
> alter table department modify id int(10), drop primary key;
有主键时,测试查询
> select * from big_data where id = ''3333333'';
+---------+--------------+------+----------------------+
| id | name | age | email |
+---------+--------------+------+----------------------+
| 3333333 | bajie3333333 | 17 | bajie3333333@163.com |
+---------+--------------+------+----------------------+
1 row in set (0.00 sec)
3).唯一索引
unique index:
两个功能: 加速查找和唯一约束(可含null)
创建唯一索引:
创建表时,创建唯一索引
create table t1(
id int not null auto_increment,
name varchar(32) not null,
email varchar(64) not null,
primary key(id),
unique index ix_name(name)
);
创建表后,创建唯一索引
create unique index un_index on big_data(email); #affected (28.47 sec) #哪个索引查起来更快: 主键 > 唯一 > 普通
有唯一索引时,测试查询
mysql> select * from big_data where email = ''bajie2222222@163.com'';
+---------+--------------+------+----------------------+
| id | name | age | email |
+---------+--------------+------+----------------------+
| 2222222 | bajie2222222 | 47 | bajie2222222@163.com |
+---------+--------------+------+----------------------+
1 row in set (0.00 sec)
删除唯一索引
drop index un_index on big_data; #和删普通索引一样
4).组合索引
组合索引是将n个列组合成一个索引
应用场景: 当频繁地使用n列来进行查询, 如 where name=''bajie'' and email=''bajie@123.com''
创建组合索引
create index index_name_email on big_data(name,email);
有组合索引时,测试查询(遵循最左前缀匹配)
select * from big_data where name=''bajie666666'' and email=''bajie666666@163.com''; #如果同时使用name和email查询时(顺序无要求),使用索引
+--------+-------------+------+---------------------+
| id | name | age | email |
+--------+-------------+------+---------------------+
| 666666 | bajie666666 | 28 | bajie666666@163.com |
+--------+-------------+------+---------------------+
1 row in set (0.00 sec)
select * from big_data where email=''bajie666666@163.com''; #单独使用email查询时, 不使用索引
+--------+-------------+------+---------------------+
| id | name | age | email |
+--------+-------------+------+---------------------+
| 666666 | bajie666666 | 28 | bajie666666@163.com |
+--------+-------------+------+---------------------+
1 row in set (1.74 sec)
select * from big_data where name=''bajie666666''; #单独使用name查询时, 使用索引
+--------+-------------+------+---------------------+
| id | name | age | email |
+--------+-------------+------+---------------------+
| 666666 | bajie666666 | 28 | bajie666666@163.com |
+--------+-------------+------+---------------------+
1 row in set (0.00 sec)
5).索引覆盖: 直接索引查询: 如果要select的字段,正好在索引表中,就会更快
select name from big_data where name=''bajie666666''; #例如name字段是索引字段, 刚好select的字段就是name字段
6).索引合并: 多个单列的索引字段查询
select * from big_data where name=''bajie666666'' and id=666666;
性能分析:
当使用多个条件进行查询时, 组合索引 > 索引合并
四.mysql索引的注意事项
1.对于索引
创建索引
命中索引
正确使用索引:
=
不正确使用索引:
like ''%xx''
or: 都是索引时除外
类型不一致: name = 7777; 本来是字符串类型,但是给了个数值类型
!= :主键除外
> < :主键除外
order by :主键除外
使用函数: where reverse(name) = ''bajie'';
组合索引的最左前缀
2.索引的注意事项
1)避免使用select *
2)count(1)或count(列)代替count(*)
3)创建表时: 尽量使用char代替varchar
4)表的字段顺序: 固定长度的字段优先
5)当经常使用多个条件查询时: 组合索引代替多个单列索引
6)尽量使用短索引: create index ix_title on t1(title(8)); 只适用于特殊的数据类型 text类型
7)使用连接join来代替子查询
8)连表时注意条件类型需一致
9)索引散列(重复少)不适用于(没必要)建索引,例如: 性别
五.解释执行(sql语句优化)
explain + sql查询: 用于显示sql执行的信息,根据参考信息可进行sql语句优化
explain select * from big_data where id != 676666 and name=''bajie666'';
+----+-------------+----------+------------+------+--------------------------+------------------+---------+-------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------+------------+------+--------------------------+------------------+---------+-------+------+----------+-----------------------+
| 1 | SIMPLE | big_data | NULL | ref | PRIMARY,index_name_email | index_name_email | 51 | const | 1 | 78.56 | Using index condition |
+----+-------------+----------+------------+------+--------------------------+------------------+---------+-------+------+----------+-----------------------+
参数说明:
select_type:
simple: 简单查询
primary: 最外层查询 (primary 初级的,主要的)
subquery: 映射为子查询
derived: 子查询 (derived 派生的)
union: 联合
union result: 使用联合的结果
table:
正在访问的表名
partitions:
分区
type:
查询时的访问(select)方式: 性能 all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const
all: 全表扫描,特别的: 如果使用了limit限制,则找到之后就不在继续向下扫描
index: 全索引扫描
range: 对索引的列进行范围查找: between...and... in >等
index_merge: 索引合并: 使用多个单列索引搜索
ref: 根据索引查找一个或多个值
eq_ref: 连接时使用: primary key 或 unique类型
const: 常量: 表最多有一个匹配行, 因为仅有一行, 在这行的列值可被优化器剩余部分认为是常数,const表很快,因为他们只读取一次
system: 系统: 表仅有一行
possible_keys:
可能使用的索引
key:
真实使用的
key_len:
mysql中使用索引的字节长度
rows:
预估行数值: mysql估计为了找到所需的行而要读取的行数
extra:
该列包含mysql解决查询的详细信息
using index: 使用了覆盖索引, 直接访问索引表,避免访问表.要和index访问类型区分开
using where: 不是所带where都显示这个, 它意味着mysql将在存储引擎检索后再进行过滤: 查询可受益于不同的索引
using temporary: 使用了临时表 (temporary 临时的)
using filesort: 使用了外部索引排序,而不是按索引次序从表里读取行
文件排序算法: 有两种: 都可以在内存或磁盘上完成
六.慢日志记录(sql语句优化)
开启慢查询日志,可以让mysql记录下查询超过指定时间的语句,通过定位分析性能的瓶颈,更好的优化数据库系统的性能
1.查询是否开启了慢查询日志
show variables like ''slow_query%'';
+---------------------+------------------------------------------------------+
| Variable_name | Value |
+---------------------+------------------------------------------------------+
| slow_query_log | OFF |
| slow_query_log_file | D:\mysql-5.7.28-winx64\data\DESKTOP-RA0BO30-slow.log | #这个目录要求mysql有可写权限, 一般设置为在mysql的数据存放目录
+---------------------+------------------------------------------------------+
2.查询慢查询的超时时间
show variables like ''long%'';
+-----------------+-----------+
| Variable_name | Value |
+-----------------+-----------+
| long_query_time | 10.000000 | #默认超过10秒才记录日志
+-----------------+-----------+
3.开启慢日志
方式一:
set global slow_query_log=1;
方式二:
[mysqld]
slow_query_log =1
slow_query_log_file=C:\mysql-5.6.40-winx64\data\localhost-slow.log
long_query_time = 1
七.分页性能相关方案
1.如何取当前表中的前10条记录,每十条取一次
select * from big_data limit 0,10;
select * from big_data limit 10,10;
select * from big_data limit 20,10;
select * from big_data limit 30,10;
...
select * from big_data limit 40000000,10; #越往后查询,需要的时间越长
...
2.最优的解决方案
select * from big_data where id > 4000000 limit 10; #下一页
select * from big_data where id < 4000000 order by id desc limit 10; #上一页
select * from (select * from big_data where id < 4000000 order by id desc limit 10) as A order by A.id; #上一页
select * from (select * from big_data where id > 4000000 limit 60) as A order by id desc limit 10; #多页查询时

List 递归循环查询所有的 子类别、子子类别、子子子类别…………递归
public List<CheckType> getAllChildTypeList(String pid, boolean isSelf){
CheckType checkType=null;
if(StringUtils.isEmpty(pid)){
List<CheckType> l=checkTypeDao.findByParentNull();
if(CollectionUtils.isEmpty(l)||l.size()==0){
return null;
}
checkType=l.get(0);
}else{
checkType=(CheckType)checkTypeDao.findById(pid);
}
List<CheckType> allList=checkTypeDao.findAllDisableFalse();
List<CheckType> newlist=new ArrayList<CheckType>();
List<CheckType> list=getChildCheckTypeList(newlist,allList,checkType);
if(isSelf){
list.add(checkType);
}
return list;
}
private List<CheckType> getChildCheckTypeList(List<CheckType> newList,List<CheckType> allList,CheckType checkType){
if(null==checkType){return newList;}
for (CheckType ct : allList) {
if(null==ct.getParent()){
continue;
}
if(ct.getParent().getId().equals(checkType.getId())){
newList.add(ct);
getChildCheckTypeList(newList,allList,ct);
}
}
return newList;
}

MySQL 5.7 对未知级别的层次结构数据的递归查询
如何解决MySQL 5.7 对未知级别的层次结构数据的递归查询?
我正在开发一个层次结构数据结构,我想在其中执行递归以获得所需的输出
id role_id reporting_to
------+-------------+-----------------
1 100 101
1 101 102
1 102 103
1 103 104
如果我给 103
作为输入角色,我希望得到以下输出
id role_id reporting_to
-----------+-------------+-----------------
1 100 101
1 101 102
1 102 103
输出应该是从输入到最后一个孩子。尝试了以下示例,但没有返回正确的输出
select id,role_id,reporting_to
from (select * from role_mapping order by reporting_to,id) rm_sorted,(select @r:=''103'') initialisation
where find_in_set(reporting_to,@r)
and length(@r := concat(@r,'',role_id))
解决方法
除非你使用函数,否则mysql5.7永远不会做递归查询。
也可以使用其他有递归的语言,如mysql5.8、oracle、java等,生成路径列,像这样(假设104是根节点)
id |
role_id |
reporting_to |
路径 |
1 |
100 |
101 |
104/103/102/101/100 |
1 |
101 |
102 |
104/103/102/101 |
1 |
102 |
103 |
104/103/102 |
1 |
103 |
104 |
104/103 |
今天的关于MySQL的递归和树父子类别的分享已经结束,谢谢您的关注,如果想了解更多关于C语言函数的递归(上)、day05 Mysql: pymysql的使用 (前端+flask+pymysql的使用) mysql索引 解释执行 慢日志 分页性能方案、List 递归循环查询所有的 子类别、子子类别、子子子类别…………递归、MySQL 5.7 对未知级别的层次结构数据的递归查询的相关知识,请在本站进行查询。