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

步履不停
풀어 주다: 2019-06-25 16:05:54
원래의
4827명이 탐색했습니다.

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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!