>데이터 베이스 >MySQL 튜토리얼 >MySQL 대형 테이블 페이징 쿼리 페이지 전환 최적화 계획

MySQL 대형 테이블 페이징 쿼리 페이지 전환 최적화 계획

步履不停
步履不停원래의
2019-06-25 16:05:544955검색

MySQL 대형 테이블 페이징 쿼리 페이지 전환 최적화 계획

mysql 페이징 쿼리는 먼저 모든 데이터를 쿼리한 다음 오프셋을 건너뛰고 제한 레코드를 가져오므로 페이지 수가 길어질수록 쿼리 시간도 길어집니다. # 🎜🎜#

일반적인 최적화 아이디어는 오프셋을 가능한 한 작게 만들기 위해 오프셋을 변환하는 것입니다. 매번 첫 번째 페이지를 쿼리하는 것이 가장 좋습니다. 즉, 오프셋은 0

#🎜 🎜#

ID로 정렬된 쿼리

1. 쿼리가 ID로 정렬되고 ID가 연속된 경우

# 🎜🎜#이것은 확인할 페이지 수를 기준으로 ID 범위를 직접 계산할 수 있는 방법이 많이 있습니다.

예를 들어 offset=40,limit=10은 쿼리를 의미합니다. 데이터가 5페이지에 있으면 5페이지에서 시작하는 ID는 41입니다. 쿼리 조건 추가: id>40 제한 10

2. 쿼리가 다음과 같은 경우 id를 기준으로 정렬했지만 id가 연속적이지 않습니다

보통 페이지 점프가 그리 크지 않기 때문에 다음 페이징 쿼리에 해당하는 새로운 오프셋과 제한을 계산할 수 있습니다. 마지막 쿼리의 레코드, 즉 이전 쿼리와의 거리 레코드 오프셋 쿼리

Paging 쿼리에는 일반적으로 오프셋과 제한이라는 두 가지 매개변수가 있습니다. 일반적으로 제한은 10으로 고정됩니다#🎜. 🎜#

그런 다음 오프셋이 너무 큰 상황을 최적화하려면 각 쿼리에서 두 개의 추가 매개 변수를 제공해야 합니다.

Parameter lastEndId: 이전 쿼리의 마지막 레코드 ID# 🎜🎜#

Parameter lastEndOffset: 이전 쿼리의 마지막 레코드에 해당합니다. 오프셋, 즉 마지막 쿼리의 오프셋+한계

첫번째 case

(실제로 두 번째와 동일): 다음 한 페이지로 이동, 쿼리 조건 추가: id>lastEndId 제한 10

  1. 두 번째 사례 : Turn 페이지를 아래로 내리고 임의의 다음 페이지로 점프하고 새 #🎜 🎜#newOffset=offset-lastEndOffset
  2. ,
  3. Add 쿼리 조건을 계산합니다. id>lastEndId offset newOffset 제한은 10이지만 예를 들어 newOffset이 여전히 매우 큰 경우 첫 번째 페이지에서 마지막 페이지로 직접 점프하면 이때 ID를 기준으로 역순으로 쿼리할 수 있습니다(원래 ID가 양수인 경우 역순으로 변경). , 역순이면 양순으로 변경), 총 개수를 기준으로 역순 쿼리에 해당하는 오프셋과 제한을 계산한 다음 newOffset = totalCount - 오프셋 - 제한, 쿼리 조건: id=totalCount, 즉 count 나오는 newOffset은 0보다 작을 수 있습니다. , 따라서 마지막 페이지의 newOffset=0, 제한 = totalCount - offset세 번째 경우 : 페이지 위로, 아무 항목으로 이동 위 페이지에서 id에 따른 역순, newOffset = lastEndOffset- offset -limit-1, 쿼리 조건: id
  4. Three, 일반적으로 사용되는 생성 시간(createTime) 등 다른 필드를 기준으로 쿼리를 정렬하는 경우# 🎜🎜#
두 번째 경우와 유사하지만 차이점은 createTime이 고유하지 않아 마지막 레코드에 해당하는 생성 시간을 확인할 수 없으며 다음 레코드는 무엇인지 알 수 없습니다.

의 한 페이지 이때 마지막 쿼리의 마지막 레코드에 해당하는 생성 시간, 몇 개의 레코드가 있는지 나타내는 요청 매개변수 lastEndCount를 추가합니다. 동시에 이는 마지막 데이터 통계를 기반으로 합니다.#🎜 🎜#

두 번째 경우에서 계산된 newOffset에 lastEndCount를 추가합니다. 이는 새로운 오프셋입니다. 두 번째 것과 동일

java 예:

/**
	 * 如果是根据创建时间排序的分页,根据上一条记录的创建时间优化分布查询
	 * 
	 * @see 将会自动添加createTime排序
	 * @param lastEndCreateTime
	 *            上一次查询的最后一条记录的创建时间
	 * @param lastEndCount 上一次查询的时间为lastEndCreateTime的数量
	 * @param lastEndOffset  上一次查询的最后一条记录对应的偏移量     offset+limit
	 **/
	public Page<T> page(QueryBuilder queryBuilder, Date lastEndCreateTime, Integer lastEndCount, Integer lastEndOffset,
			int offset, int limit) {
		FromBuilder fromBuilder = queryBuilder.from(getModelClass());
		Page<T> page = new Page<>();
		int count = dao.count(fromBuilder);
		page.setTotal(count);
		if (count == 0) {
			return page;
		}
		if (offset == 0 || lastEndCreateTime == null || lastEndCount == null || lastEndOffset == null) {
			List<T> list = dao.find(
					SelectBuilder.selectFrom(fromBuilder.offsetLimit(offset, limit).order().desc("createTime").end()));
			page.setData(list);
			return page;
		}
		boolean isForward = offset >= lastEndOffset;
		if (isForward) {
			int calcOffset = offset - lastEndOffset + lastEndCount;
			int calcOffsetFormEnd = count - offset - limit;
			if (calcOffsetFormEnd <= calcOffset) {
				isForward = false;
				if (calcOffsetFormEnd > 0) {
					fromBuilder.order().asc("createTime").end().offsetLimit(calcOffsetFormEnd, limit);
				} else {
					fromBuilder.order().asc("createTime").end().offsetLimit(0, calcOffsetFormEnd + limit);
				}
			} else {
				fromBuilder.where().andLe("createTime", lastEndCreateTime).end().order().desc("createTime").end()
						.offsetLimit(calcOffset, limit);
			}
		} else {
			fromBuilder.where().andGe("createTime", lastEndCreateTime).end().order().asc("createTime").end()
					.offsetLimit(lastEndOffset - offset - limit - 1 + lastEndCount, limit);
		}
		List<T> list = dao.find(SelectBuilder.selectFrom(fromBuilder));
		if (!isForward) {
			list.sort(new Comparator<T>() {
				@Override
				public int compare(T o1, T o2) {
					return o1.getCreateTime().before(o2.getCreateTime()) ? 1 : -1;
				}
			});
		}
		page.setData(list);
		return page;
	} <p> 부트스트랩 테이블을 기반으로 한 프런트 엔드 js 매개변수</p>
<pre class="brush:php;toolbar:false">    this.lastEndCreateTime = null;
    this.currentEndCreateTime = null;
    
    this.isRefresh = false;        
      this.currentEndOffset = 0;
        this.lastEndOffset = 0;
        this.lastEndCount = 0;
        this.currentEndCount = 0;
        $("#" + this.tableId).bootstrapTable({
            url: url,
            method: 'get',
            contentType: "application/x-www-form-urlencoded",//请求数据内容格式 默认是 application/json 自己根据格式自行服务端处理
            dataType:"json",
            dataField:"data",
            pagination: true,
            sidePagination: "server", // 服务端请求
            pageList: [10, 25, 50, 100, 200],
            search: true,
            showRefresh: true,
            toolbar: "#" + tableId + "Toolbar",
            iconSize: "outline",
            icons: {
                refresh: "icon fa-refresh",
            },
            queryParams: function(params){
            	if(params.offset == 0){
            		this.currentEndOffset = params.offset + params.limit;
            	}else{
            		if(params.offset + params.limit==this.currentEndOffset){ 
            			//刷新
            			this.isRefresh = true;
            			params.lastEndCreateTime = this.lastEndCreateTime;
                		params.lastEndOffset = this.lastEndOffset;
                		params.lastEndCount = this.lastEndCount;
            		}else{ 
            			console.log(this.currentEndCount);
            			//跳页
            			this.isRefresh = false;
            			params.lastEndCreateTime = this.currentEndCreateTime;
                		params.lastEndOffset = this.currentEndOffset;
                		params.lastEndCount = this.currentEndCount;
                		this.lastEndOffset = this.currentEndOffset;
                		this.currentEndOffset = params.offset + params.limit;
                		console.log(params.lastEndOffset+","+params.lastEndCreateTime);
                		
            		}
            	}
            	return params;
            },
            onSearch: function (text) {
                this.keyword = text;
            },
            onPostBody : onPostBody,
            onLoadSuccess: function (resp) {
            	
            	if(resp.code!=0){
            		alertUtils.error(resp.msg);
            	}
               
                var data = resp.data;
                var dateLength = data.length;
                if(dateLength==0){
                	return;
                }
                if(!this.isRefresh){
                	 this.lastEndCreateTime =  this.currentEndCreateTime;
                     this.currentEndCreateTime = data[data.length-1].createTime;
                     this.lastEndCount = this.currentEndCount;
                     this.currentEndCount = 0;
                     for (var i = 0; i < resp.data.length; i++) {
						var item = resp.data[i];
						if(item.createTime === this.currentEndCreateTime){
							this.currentEndCount++;
						}
					}
                }
                
            }
        });
#🎜 🎜#더 많은 MySQL 관련 기술 기사를 보려면

MySQLTutorial

열을 방문하여 알아보세요!

위 내용은 MySQL 대형 테이블 페이징 쿼리 페이지 전환 최적화 계획의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.