Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【瑞吉外卖】day07:新增套餐、套餐分页查询、 删除套餐

【瑞吉外卖】day07:新增套餐、套餐分页查询、 删除套餐

作者头像
陶然同学
发布于 2023-02-27 05:20:57
发布于 2023-02-27 05:20:57
1.5K00
代码可运行
举报
文章被收录于专栏:陶然同学博客陶然同学博客
运行总次数:0
代码可运行

目录

1. 新增套餐

1.1 需求分析

1.2 数据模型

1.3 准备工作

1.4 前端页面分析

1.5 代码开发

2. 套餐分页查询

2.1 需求分析

2.2 前端页面分析

2.3 代码开发

2.4 功能测试

3. 删除套餐

3.1 需求分析

3.2 前端页面分析

3.3 代码开发

3.4 功能测试

1. 新增套餐

1.1 需求分析

套餐就是菜品的集合。

后台系统中可以管理套餐信息,通过新增套餐功能来添加一个新的套餐,在添加套餐时需要选择当前套餐所属的套餐分类和包含的菜品,并且需要上传套餐对应的图片,在移动端会按照套餐分类来展示对应的套餐。

1.2 数据模型

新增套餐,其实就是将新增页面录入的套餐信息插入到setmeal表,还需要向setmeal_dish表插入套餐和菜品关联数据。所以在新增套餐时,涉及到两个表:

说明

备注

setmeal

套餐表

存储套餐的基本信息

setmeal_dish

套餐菜品关系表

存储套餐关联的菜品的信息(一个套餐可以关联多个菜品)

两张表具体的表结构如下:

1). 套餐表setmeal

在该表中,套餐名称name字段是不允许重复的,在建表时,已经创建了唯一索引。

2). 套餐菜品关系表setmeal_dish

在该表中,菜品的名称name,菜品的原价price 实际上都是冗余字段,因为我们在这张表中存储了菜品的ID(dish_id),根据该ID我们就可以查询出name,price的数据信息,而这里我们又存储了name,price,这样的话,我们在后续的查询展示操作中,就不需要再去查询数据库获取菜品名称和原价了,这样可以简化我们的操作。

1.3 准备工作

在开发业务功能前,先将需要用到的类和接口基本结构创建好,在做这一块儿的准备工作时,我们无需准备Setmeal的相关实体类、Mapper接口、Service接口及实现,因为之前在做分类管理的时候,我们已经引入了Setmeal的相关基础代码。 接下来,我们就来完成以下的几步准备工作:

1). 实体类 SetmealDish

ps.直接从课程资料中导入即可,Setmeal实体前面课程中已经导入过了。

所属包: com.itheima.reggie.entity

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;/**
 * 套餐菜品关系
 */
@Data
public class SetmealDish implements Serializable {
    private static final long serialVersionUID = 1L;private Long id;//套餐id
    private Long setmealId;//菜品id
    private Long dishId;//菜品名称 (冗余字段)
    private String name;
    
    //菜品原价
    private BigDecimal price;
    
    //份数
    private Integer copies;//排序
    private Integer sort;
​
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
​
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
​
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;
​
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;//是否删除
    private Integer isDeleted;
}

2). DTO SetmealDto

该数据传输对象DTO,主要用于封装页面在新增套餐时传递过来的json格式的数据,其中包含套餐的基本信息,还包含套餐关联的菜品集合。直接从课程资料中导入即可。

所属包: com.itheima.reggie.dto

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import com.itheima.reggie.entity.Setmeal;
import com.itheima.reggie.entity.SetmealDish;
import lombok.Data;
import java.util.List;
​
@Data
public class SetmealDto extends Setmeal {private List<SetmealDish> setmealDishes;//套餐关联的菜品集合
    
    private String categoryName;//分类名称
}

3). Mapper接口 SetmealDishMapper

所属包: com.itheima.reggie.mapper

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.reggie.entity.SetmealDish;
import org.apache.ibatis.annotations.Mapper;
​
@Mapper
public interface SetmealDishMapper extends BaseMapper<SetmealDish> {
}

4). 业务层接口 SetmealDishService

所属包: com.itheima.reggie.service

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.reggie.entity.SetmealDish;public interface SetmealDishService extends IService<SetmealDish> {
}

5). 业务层实现类 SetmealDishServiceImpl

所属包: com.itheima.reggie.service.impl

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.reggie.entity.SetmealDish;
import com.itheima.reggie.mapper.SetmealDishMapper;
import com.itheima.reggie.service.SetmealDishService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
​
@Service
@Slf4j
public class SetmealDishServiceImpl extends ServiceImpl<SetmealDishMapper,SetmealDish> implements SetmealDishService {
}

6). 控制层 SetmealController

套餐管理的相关业务,我们都统一在 SetmealController 中进行统一处理操作。

所属包: com.itheima.reggie.service.impl

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import com.itheima.reggie.service.SetmealDishService;
import com.itheima.reggie.service.SetmealService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;/**
 * 套餐管理
 */
@RestController
@RequestMapping("/setmeal")
@Slf4j
public class SetmealController {
    @Autowired
    private SetmealService setmealService;
    @Autowired
    private SetmealDishService setmealDishService;
}    

1.4 前端页面分析

服务端的基础准备工作我们准备完毕之后,在进行代码开发之前,需要梳理一下新增套餐时前端页面和服务端的交互过程:

1). 点击新建套餐按钮,访问页面(backend/page/combo/add.html),页面加载发送ajax请求,请求服务端获取套餐分类数据并展示到下拉框中(==已实现==)

获取套餐分类列表的功能我们不用开发,之前已经开发完成了,之前查询时type传递的是1,查询菜品分类; 本次查询时,传递的type为2,查询套餐分类列表。

2). 访问页面(backend/page/combo/add.html),页面加载时发送ajax请求,请求服务端获取菜品分类数据并展示到添加菜品窗口中(==已实现==)

本次查询分类列表,传递的type为1,表示需要查询的是菜品的分类。查询菜品分类的目的,是添加套餐关联的菜品时,我们需要根据菜品分类,来过滤查询菜品信息。查询菜品分类列表的代码已经实现, 具体展示效果如下:

3). 当点击添加菜品窗口左侧菜单的某一个分类, 页面发送ajax请求,请求服务端,根据菜品分类查询对应的菜品数据并展示到添加菜品窗口中

4). 页面发送请求进行图片上传,请求服务端将图片保存到服务器(==已实现==)

5). 页面发送请求进行图片下载,将上传的图片进行回显(==已实现==)

6). 点击保存按钮,发送ajax请求,将套餐相关数据以json形式提交到服务端

经过上述的页面解析及流程分析,我们发送这里需要发送的请求有5个,分别是 :

A. 根据传递的参数,查询套餐分类列表

B. 根据传递的参数,查询菜品分类列表

C. 图片上传

D. 图片下载展示

E. 根据菜品分类ID,查询菜品列表

F. 保存套餐信息

而对于以上的前4个功能我们都已经实现, 所以我们接下来需要开发的功能主要是最后两项, 具体的请求信息如下:

1). 根据分类ID查询菜品列表

请求

说明

请求方式

GET

请求路径

/dish/list

请求参数

?categoryId=1397844263642378242

2). 保存套餐信息

请求

说明

请求方式

POST

请求路径

/setmeal

请求参数

json格式数据

传递的json格式数据如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
    "name":"营养超值工作餐",
    "categoryId":"1399923597874081794",
    "price":3800,
    "code":"",
    "image":"9cd7a80a-da54-4f46-bf33-af3576514cec.jpg",
    "description":"营养超值工作餐",
    "dishList":[],
    "status":1,
    "idType":"1399923597874081794",
    "setmealDishes":[
        {"copies":2,"dishId":"1423329009705463809","name":"米饭","price":200},
        {"copies":1,"dishId":"1423328152549109762","name":"可乐","price":500},
        {"copies":1,"dishId":"1397853890262118402","name":"鱼香肉丝","price":3800}
    ]
}

1.5 代码开发

上面我们已经分析了接下来我们需要实现的两个功能,接下来我们就需要根据上述的分析,来完成具体的功能实现。

1.5.1 根据分类查询菜品

1.5.1.1 功能实现

在当前的需求中,我们只需要根据页面传递的菜品分类的ID(categoryId)来查询菜品列表即可,我们可以直接定义一个DishController的方法,声明一个Long类型的categoryId,这样做是没问题的。但是考虑到该方法的拓展性,我们在这里定义方法时,通过Dish这个实体来接收参数。

在DishController中定义方法list,接收Dish类型的参数:

在查询时,需要根据菜品分类categoryId进行查询,并且还要限定菜品的状态为起售状态(status为1),然后对查询的结果进行排序。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
* 根据条件查询对应的菜品数据
* @param dish
* @return
*/
@GetMapping("/list")
public R<List<Dish>> list(Dish dish){
    //构造查询条件
    LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(dish.getCategoryId() != null ,Dish::getCategoryId,dish.getCategoryId());
    //添加条件,查询状态为1(起售状态)的菜品
    queryWrapper.eq(Dish::getStatus,1);
    //添加排序条件
    queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
    
    List<Dish> list = dishService.list(queryWrapper);
    
    return R.success(list);
}

1.5.1.2 功能测试

代码编写完毕,我们重新启动服务器,进行测试,可以通过debug断点跟踪的形式查看页面传递的参数封装情况,及响应给页面的数据信息。

1.5.2 保存套餐

1.5.2.1 功能实现

在进行套餐信息保存时,前端提交的数据,不仅包含套餐的基本信息,还包含套餐关联的菜品列表数据 setmealDishes。所以这个时候我们使用Setmeal就不能完成参数的封装了,我们需要在Setmeal的基本属性的基础上,再扩充一个属性 setmealDishes 来接收页面传递的套餐关联的菜品列表,而我们在准备工作中,导入进来的SetmealDto能够满足这个需求。

1). SetmealController中定义方法save,新增套餐

在该Controller的方法中,我们不仅需要保存套餐的基本信息,还需要保存套餐关联的菜品数据,所以我们需要再该方法中调用业务层方法,完成两块数据的保存。

页面传递的数据是json格式,需要在方法形参前面加上@RequestBody注解, 完成参数封装。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@PostMapping
public R<String> save(@RequestBody SetmealDto setmealDto){
    log.info("套餐信息:{}",setmealDto);
​
    setmealService.saveWithDish(setmealDto);return R.success("新增套餐成功");
}

2). SetmealService中定义方法saveWithDish

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 新增套餐,同时需要保存套餐和菜品的关联关系
 * @param setmealDto
 */
public void saveWithDish(SetmealDto setmealDto);

3). SetmealServiceImpl实现方法saveWithDish

具体逻辑:

A. 保存套餐基本信息

B. 获取套餐关联的菜品集合,并为集合中的每一个元素赋值套餐ID(setmealId)

C. 批量保存套餐关联的菜品集合

代码实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 新增套餐,同时需要保存套餐和菜品的关联关系
 * @param setmealDto
 */
@Transactional
public void saveWithDish(SetmealDto setmealDto) {
    //保存套餐的基本信息,操作setmeal,执行insert操作
    this.save(setmealDto);
​
    List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();
    setmealDishes.stream().map((item) -> {
        item.setSetmealId(setmealDto.getId());
        return item;
    }).collect(Collectors.toList());//保存套餐和菜品的关联信息,操作setmeal_dish,执行insert操作
    setmealDishService.saveBatch(setmealDishes);
}

1.5.2.2 功能测试

代码编写完毕,我们重新启动服务器,进行测试,可以通过debug断点跟踪的形式查看页面传递的参数封装情况,及套餐相关数据的保存情况。

录入表单数据:

debug跟踪数据封装:

跟踪数据库保存的数据:

2. 套餐分页查询

2.1 需求分析

系统中的套餐数据很多的时候,如果在一个页面中全部展示出来会显得比较乱,不便于查看,所以一般的系统中都会以分页的方式来展示列表数据。

在进行套餐数据的分页查询时,除了传递分页参数以外,还可以传递一个可选的条件(套餐名称)。查询返回的字段中,包含套餐的基本信息之外,还有一个套餐的分类名称,在查询时,需要关联查询这个字段。

2.2 前端页面分析

在开发代码之前,需要梳理一下套餐分页查询时前端页面和服务端的交互过程:

1). 访问页面(backend/page/combo/list.html),页面加载时,会自动发送ajax请求,将分页查询参数(page、pageSize、name)提交到服务端,获取分页数据

2). 在列表渲染展示时,页面发送请求,请求服务端进行图片下载,用于页面图片展示(已实现)

而对于以上的流程中涉及到2个功能,文件下载功能我们已经实现,本小节我们主要实现列表分页查询功能, 具体的请求信息如下:

请求

说明

请求方式

GET

请求路径

/setmeal/page

请求参数

?page=1&pageSize=10&name=xxx

2.3 代码开发

2.3.1 基本信息查询

上述我们已经分析列表分页查询功能的请求信息,接下来我们就在SetmealController中创建套餐分页查询方法。

该方法的逻辑如下:

1). 构建分页条件对象

2). 构建查询条件对象,如果传递了套餐名称,根据套餐名称模糊查询, 并对结果按修改时间降序排序

3). 执行分页查询

4). 组装数据并返回

代码实现 :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
  * 套餐分页查询
  * @param page
  * @param pageSize
  * @param name
  * @return
  */
@GetMapping("/page")
public R<Page> page(int page,int pageSize,String name){
    //分页构造器对象
    Page<Setmeal> pageInfo = new Page<>(page,pageSize);
    
    LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
    //添加查询条件,根据name进行like模糊查询
    queryWrapper.like(name != null,Setmeal::getName,name);
    //添加排序条件,根据更新时间降序排列
    queryWrapper.orderByDesc(Setmeal::getUpdateTime);
​
    setmealService.page(pageInfo,queryWrapper);
    return R.success(pageInfo);
}

2.3.2 问题分析

基本分页查询代码编写完毕后,重启服务,测试列表查询,我们发现, 列表页面的数据可以展示出来, 但是套餐分类名称没有展示出来。

这是因为在服务端仅返回分类ID(categoryId), 而页面展示需要的是categoryName属性。

2.3.3 功能完善

在查询套餐信息时, 只包含套餐的基本信息, 并不包含套餐的分类名称, 所以在这里查询到套餐的基本信息后, 还需要根据分类ID(categoryId), 查询套餐分类名称(categoryName),并最终将套餐的基本信息及分类名称信息封装到SetmealDto(在第一小节已经导入)中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Data
public class SetmealDto extends Setmeal {
    private List<SetmealDish> setmealDishes; //套餐关联菜品列表
    private String categoryName;//套餐分类名称
}

完善后代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
* 套餐分页查询
* @param page
* @param pageSize
* @param name
* @return
*/
@GetMapping("/page")
public R<Page> page(int page,int pageSize,String name){
    //分页构造器对象
    Page<Setmeal> pageInfo = new Page<>(page,pageSize);
    Page<SetmealDto> dtoPage = new Page<>();
​
    LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
    //添加查询条件,根据name进行like模糊查询
    queryWrapper.like(name != null,Setmeal::getName,name);
    //添加排序条件,根据更新时间降序排列
    queryWrapper.orderByDesc(Setmeal::getUpdateTime);
​
    setmealService.page(pageInfo,queryWrapper);//对象拷贝
    BeanUtils.copyProperties(pageInfo,dtoPage,"records");
    List<Setmeal> records = pageInfo.getRecords();
​
    List<SetmealDto> list = records.stream().map((item) -> {
        SetmealDto setmealDto = new SetmealDto();
        //对象拷贝
        BeanUtils.copyProperties(item,setmealDto);
        //分类id
        Long categoryId = item.getCategoryId();
        //根据分类id查询分类对象
        Category category = categoryService.getById(categoryId);
        if(category != null){
            //分类名称
            String categoryName = category.getName();
            setmealDto.setCategoryName(categoryName);
        }
        return setmealDto;
    }).collect(Collectors.toList());
​
    dtoPage.setRecords(list);
    return R.success(dtoPage);
}

2.4 功能测试

代码完善后,重启服务,测试列表查询,我们发现, 抓取浏览器的请求响应数据,我们可以获取到套餐分类名称categoryName,也可以在列表页面展示出来 。

3. 删除套餐

3.1 需求分析

在套餐管理列表页面,点击删除按钮,可以删除对应的套餐信息。也可以通过复选框选择多个套餐,点击批量删除按钮一次删除多个套餐。注意,对于状态为售卖中的套餐不能删除,需要先停售,然后才能删除。

3.2 前端页面分析

在开发代码之前,需要梳理一下删除套餐时前端页面和服务端的交互过程:

1). 点击删除, 删除单个套餐时,页面发送ajax请求,根据套餐id删除对应套餐

2). 删除多个套餐时,页面发送ajax请求,根据提交的多个套餐id删除对应套餐

开发删除套餐功能,其实就是在服务端编写代码去处理前端页面发送的这2次请求即可,一次请求为根据ID删除,一次请求为根据ID批量删除。

观察删除单个套餐和批量删除套餐的请求信息可以发现,两种请求的地址请求方式都是相同的,不同的则是传递的id个数,所以在服务端可以提供一个方法来统一处理。

具体的请求信息如下:

请求

说明

请求方式

DELETE

请求路径

/setmeal

请求参数

?ids=1423640210125656065,1423338765002256385

3.3 代码开发

删除套餐的流程及请求信息,我们分析完毕之后,就来完成服务端的逻辑开发。在服务端的逻辑中, 删除套餐时, 我们不仅要删除套餐, 还要删除套餐与菜品的关联关系。

1). 在SetmealController中创建delete方法

我们可以先测试在delete方法中接收页面提交的参数,具体逻辑后续再完善:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 删除套餐
 * @param ids
 * @return
 */
@DeleteMapping
public R<String> delete(@RequestParam List<Long> ids){
    log.info("ids:{}",ids);
    return R.success("套餐数据删除成功");
}

编写完代码,我们重启服务之后,访问套餐列表页面,勾选复选框,然后点击"批量删除",我们可以看到服务端可以接收到集合参数ids,并且在控制台也可以输出对应的数据 。

2). SetmealService接口定义方法removeWithDish

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 删除套餐,同时需要删除套餐和菜品的关联数据
 * @param ids
 */
public void removeWithDish(List<Long> ids);

3). SetmealServiceImpl中实现方法removeWithDish

该业务层方法具体的逻辑为:

A. 查询该批次套餐中是否存在售卖中的套餐, 如果存在, 不允许删除

B. 删除套餐数据

C. 删除套餐关联的菜品数据

代码实现为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
* 删除套餐,同时需要删除套餐和菜品的关联数据
* @param ids
*/
@Transactional
public void removeWithDish(List<Long> ids) {
    //select count(*) from setmeal where id in (1,2,3) and status = 1
    //查询套餐状态,确定是否可用删除
    LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper();
    queryWrapper.in(Setmeal::getId,ids);
    queryWrapper.eq(Setmeal::getStatus,1);
​
    int count = this.count(queryWrapper);
    if(count > 0){
        //如果不能删除,抛出一个业务异常
        throw new CustomException("套餐正在售卖中,不能删除");
    }//如果可以删除,先删除套餐表中的数据---setmeal
    this.removeByIds(ids);//delete from setmeal_dish where setmeal_id in (1,2,3)
    LambdaQueryWrapper<SetmealDish> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    lambdaQueryWrapper.in(SetmealDish::getSetmealId,ids);
    //删除关系表中的数据----setmeal_dish
    setmealDishService.remove(lambdaQueryWrapper);
}

由于当前的业务方法中存在多次数据库操作,为了保证事务的完整性,需要在方法上加注解 @Transactional 来控制事务。

4). 完善SetmealController代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 删除套餐
 * @param ids
 * @return
 */
@DeleteMapping
public R<String> delete(@RequestParam List<Long> ids){
    log.info("ids:{}",ids);
    setmealService.removeWithDish(ids);
    return R.success("套餐数据删除成功");
}

3.4 功能测试

代码完善后,重启服务,测试套餐的删除功能,主要测试以下几种情况。

1). 删除正在启用的套餐

2). 执行批量操作, 删除两条记录, 一个启售的, 一个停售的

由于当前我们并未实现启售/停售功能,所以我们需要手动修改数据库表结构的status状态,将其中的一条记录status修改为0。

3). 删除已经停售的套餐信息,执行删除之后, 检查数据库表结构 setmeal , setmeal_dish表中的数据

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-11-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Oracle SQL性能优化
(1)      选择最有效率的表名顺序(只在基于规则的优化器中有效): ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(基础表 driving table)将被最先处理,在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表。如果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指那个被其他表所引用的表. (2)      WHERE子句中的连接顺序.: ORACLE采用自下而上
猿人谷
2018/01/17
3.2K0
Oracle SQL性能优化40条,值得收藏
语法分析> 语义分析> 视图转换 >表达式转换> 选择优化器 >选择连接方式 >选择连接顺序 >选择数据的搜索路径 >运行“执行计划”
数据和云
2019/05/13
2.9K0
SQL 语句分析 -explain 执行计划详解
实际生产环境中,为了知道SQL语句的执行过程具体,我们可以使用explain + SQL语句来查看。
技能锦囊
2020/05/26
1.4K0
Oracle-index索引解读
数据在磁盘上是以块的形式存储的。为确保对磁盘操作的原子性,访问数据的时候会一并访问所有数据块。磁盘上的这些数据块与链表类似,即它们都包含一个数据段和一个指针,指针指向下一个节点(数据块)的内存地址,而且它们都不需要连续存储(即逻辑上相邻的数据块在物理上可以相隔很远)。
小小工匠
2021/08/16
1.1K0
SQL优化二(SQL性能调优)
一·、前言:这篇博文内容非原创,是我们公司的架构师给我们做技术培训的时候讲的内容,我稍微整理了下,借花献佛。这篇博文只是做一个大概的科普介绍,毕竟SQL优化的知识太大了,几乎可以用一本书来介绍。另外,博主对SQL优化也是刚刚接触,也有很多不了解的地方,说的不对的地方,还请大家指正,共勉! 二、oracle服务器,所谓oracle服务器指的是一个数据库管理系统,它包括一个oracle实例(动态)和一个oracle数据库(静态)。 oracle实例是一个运行的概念,提供了一种访问数据库的方式,由SGA和一些后
JMCui
2018/03/15
1.6K0
SQL优化二(SQL性能调优)
分享:Oracle sql语句优化
最近做查询时,写的一条查询语句用了两个IN,导致tuexdo服务积压了不少,用户没骂就不错了。最后经过技术经理的点拨,sql语句性能提升了大约10倍,主要用了表连接、建索引、exists。这才感叹SQL性能优化的重要性啊,网上搜了半天,找到一篇令我非常满意的日志,忍不住分享之:
williamwong
2018/07/24
3.5K0
分享:Oracle sql语句优化
SQL优化法则小记
SQL优化技巧 1.选择最有效率的表名顺序(只在基于规则的优化器中有效): oracle的解析器按照从右到左的顺序处理 from 子句中的表名,from子句中写在最后的表(基础表 driving table)将被最先处理,在 from 子句中包含多个表的情况下, 你必须选择记录条数最少的表作为基础表。如果有 3 个以上的表连接查询, 那就需 要选择交叉表(intersection table)作为基础表, 交叉表是指那个被其他表所引用的表. 2.where子句中的连接顺序:
赵腰静
2018/03/09
2.3K0
高效SQL语句必杀技
        No SQL,No cost. SQL语句是造成数据库开销最大的部分。而不良SQL写法直接导致数据库系统性能下降的情形比比皆是。那么如何才能称得 上高效的SQL语句呢?一是查询优化器为当前的SQL语句生成最佳的执行计划,保证数据读写使用最佳路径;二是设置合理的物理存储结构,如表 的类型,字段的顺序,字段的数据类型等。本文主要描述如何编写高效的SQL语句并给出示例。下面的描述主要分为三个部分,一是编写高效SQL 语句,二是使用索引提高查询性能的部分,三是总结部分。
Leshami
2018/08/14
1.5K0
SQL高效与低效
(6) 使用DECODE函数来减少处理时间 使用DECODE函数可以避免重复描述相同记录或重复连结相同的表 例如:
一头小山猪
2020/04/10
5710
Oracle查询性能优化
原则一:注意WHERE子句中的连接顺序: ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾. 尤其是“主键ID=?”这样的条件。
用户7353950
2022/05/10
2.6K0
SQL 性能调优
我们要做到不但会写SQL,还要做到写出性能优良的SQL,以下为笔者学习、摘录、并汇总部分资料与大家分享! (1)选择最有效率的表名顺序(只在基于规则的优化器中有效) ORACLE 的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(基础表 driving table)将被最先处理,在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表。如果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指那
似水的流年
2018/01/18
3.2K0
Oracle优化
本文内容来源作者实践、公司内部资源及国外文章翻译,大家觉得有样可以拿走,高兴时可以在你文章末尾留下博客地址引用。
jack.yang
2025/04/05
2430
Java SQL语句优化经验
. (1) 选择最有效率的表名顺序(只在基于规则的seo/' target='_blank'>优化器中有效): ORACLE 的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(基础表 driving table)将被最先处理,在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表。如果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指那个被其他表所引用的表. (2) WHERE子句中的连接顺序.:
企鹅号小编
2018/02/02
2.9K0
Java SQL语句优化经验
【DB笔试面试570】在Oracle中,SQL优化在写法上有哪些常用的方法?
一般在书写SQL时需要注意哪些问题,如何书写可以提高查询的效率呢?可以从以下几个方面去考虑:
AiDBA宝典
2019/09/29
3.9K0
Oracle SQL调优系列之优化器基础知识
本博客介绍一下属于oracle优化器范畴的一些基础知识,访问数据的方法,分为直接访问数据的方法和访问索引的方法两种,然后有了这些基础知识后,可以参考学习我的另外一篇博客:Oracle优化器简介,对Oracle 的一些原理的简单介绍,对于学习oracle方面的SQL优化是有帮助的,https://blog.csdn.net/u014427391/article/details/87656904
SmileNicky
2022/05/07
9140
Oracle SQL调优系列之优化器基础知识
sql优化40秒到0.1秒的奥秘
经和运维配合查看,发现是SQL语句问题,有个sql查询脚本执行竟然消耗了40秒,我拿出来自己执行发现亦是如此。
灬沙师弟
2023/09/06
3690
sql优化40秒到0.1秒的奥秘
oracle的sql语句的简单优化
ORACLE的这个功能大大地提高了SQL的执行性能并节省了内存的使用: 我们发现,单表数据的统计比多表统计的速度完全是两个概念.单表统计可能只要0.02秒,但是2张表联合统计就可能要几 十表了. 这是因为ORACLE只对简单的表提供高速缓冲(cache buffering) ,这个功能并不适用于多表连接查询… 数据库管理员必须在init.ora中为这个区域设置合适的参数,当这个内存区域越大,就可以保留更多的语句, 当然被共享的可能性也就越大了. 当你向ORACLE提交一个SQL语句,ORACLE会首先在这块内存中查找相同的语句. 这里需要注明的是,ORACLE对两者采取的是一种严格匹配,要达成共享,SQL语句必须 完全相同(包括空格,换行等).
微醺
2019/01/17
1.4K0
【DB笔试面试593】在Oracle中,表的访问方式有哪几种?
访问表的方式也叫优化器访问路径,主要有3种访问路径:全表扫描(FULL TABLE SCAN,FTS)、索引扫描(INDEX SCAN)和ROWID访问。
AiDBA宝典
2019/09/29
1.3K0
【DB笔试面试593】在Oracle中,表的访问方式有哪几种?
sql优化的几种方法面试题_mysql存储过程面试题
(1)索引一旦建立,** Oracle管理系统会对其进行自动维护**, 而且由Oracle管理系统决定何时使用索引
全栈程序员站长
2022/09/27
9090
Oracle优化器基础知识
本博客介绍一下属于oracle优化器范畴的一些基础知识,访问数据的方法,分为直接访问数据的方法和访问索引的方法两种,然后有了这些基础知识后,可以参考学习我的另外一篇博客:Oracle优化器简介,对Oracle 的一些原理的简单介绍,对于学习oracle方面的SQL优化是有帮助的,https://cloud.tencent.com/developer/article/1399323
SmileNicky
2019/03/20
7250
Oracle优化器基础知识
相关推荐
Oracle SQL性能优化
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验