찾다

 >  Q&A  >  본문

分页显示 - MySQL分页查询,是用LIMIT m,n,还是先查出所有ID再在前端分页?

用传统的LIMIT m, n做分页查询需要这么几步:

  1. SELECT COUNT(*) FROM table WHERE condition ORDER BY ...查到总数并算出有多少页;

  2. SELECT columns FROM table WHERE condition ORDER BY ... LIMIT 0, 100显示第一页(假设每页有100行),如果用SQL_CALC_FOUND_ROWS这个参数的话,可以跟前一条合并成一条SQL;

  3. 点“下一页”时,用SELECT columns FROM table WHERE condition ORDER BY ... LIMIT 100, 100查;

  4. ...

这样做往往花费很大,因为WHERE condition有可能是全表扫描。如果MySQL没开缓存的话,每翻一页可能非常慢。

因此我就用一种新的办法:

  1. SELECT id FROM table WHERE condition ORDER BY ...得到所有相符的ID,如果数据量太大(比如表中有1,000,000行),我们就限制一下行数(比如限制最多查10,000,就用LIMIT 10000),于是这些ID就通过动态页面或Ajax(以JS代码或JSON的形式)被传到了前端;

  2. 前端JS选取前100个ID作为第一页,发送一个带这100个ID的查询请求,后端其实处理SELECT columns FROM table WHERE id IN (id_0, id_1, ..., id_99)这么一个查询;

  3. 点“下一页”时,查询是SELECT columns FROM table WHERE id IN (id_100, id_101, ..., id_199)

  4. ...

这种方法只需要做一次条件查询(慢),列表数据其实都是主键查询(快)。

我在一个业余项目中用了这个办法,详见:(http://) www.chess-wizard.com/base/ (第一页数据被写在JSP页面里,有利于SEO).

我要求团队成员都用这种方式来处理分页,他们却并不认同 :-(

难道LIMIT m, n是分页查询的标准做法唯一途径吗?

巴扎黑巴扎黑2831일 전1016

모든 응답(6)나는 대답할 것이다

  • 大家讲道理

    大家讲道理2017-04-17 16:40:37

    id>$id 제한 $limit; 전달 매개변수 $offset,$limit=100;

    첫 번째 페이지:$offset = 0

    ID 제한 $limit에 따라 테이블 순서에서 ID, 이름을 선택합니다.

    두 번째 페이지: $offset은 첫 번째 페이지에서 반환된 ID입니다.

    ID 제한 $limit에 따라 id>$offset 순서가 있는 테이블에서 id,name을 선택합니다.

    회신하다
    0
  • 黄舟

    黄舟2017-04-17 16:40:37

    페이징이 느린 주된 이유는 첫 번째 단계(기준에 맞는 레코드 검색, 정렬, 현재 페이지의 행 선택)가 느리기 때문입니다. 이 단계에서는 언급한 방법이 개선되지 않았습니다.

    또 다른 경우에는 조건에 맞는 레코드를 얻기 위해 첫 번째 단계에서 소수의 테이블을 사용할 수 있지만, 이때 실행 계획이 선택된 경우 세부 행 데이터를 얻기 위해서는 다른 여러 테이블과 연결되어야 합니다. 데이터베이스가 올바르지 않아 속도가 매우 느려집니다. 이때 @abul의 메소드를 이용하면 먼저 작은 테이블에서 조건에 맞는 레코드 ID를 제거한 후 다른 테이블과 연관시킬 수 있다.

    이러한 프로세스는 데이터베이스 내에서 완료되므로 데이터를 프런트 엔드로 전송할 필요가 없습니다.
    1. 결과 집합의 데이터 양이 조건을 충족하는 경우. 크기가 크면 데이터베이스가 모든 ID와 교차 네트워크를 쿼리합니다. 전송 비용이 매우 높으며 언급한 최대 항목 10,000개 제한이 모든 시나리오를 충족하지 못할 수도 있습니다.
    2. 사용자는 처음 몇 페이지의 내용만 읽는 경우가 많으며, 모든 ID를 한꺼번에 꺼내는 것은 실제로 낭비입니다.
    3. 첫 번째 쿼리와 두 번째 쿼리 사이에 데이터가 변경되면 사용자가 얻은 결과 집합이 부정확하게 됩니다. 쿼리 결과의 정확성 요구 사항을 기준으로 가능한지 여부를 판단해야 합니다.
    또한, 쿼리된 데이터가 인지도가 높을 경우 redis와 유사한 캐시에 넣어 시스템의 전체 부하를 줄이는 것을 고려할 수 있습니다. 프론트 엔드에만 배치하면 재사용률도 높아집니다. 낮은.

    절대적으로 올바른 원칙을 말해야 한다면 실제로는 말도 안되는 소리입니다. 비즈니스 시나리오의 요구 사항과 각 솔루션의 장단점을 기반으로 판단하고 선택하세요.

    회신하다
    0
  • ringa_lee

    ringa_lee2017-04-17 16:40:37

    1. mysql은 왜 캐싱을 활성화하지 않나요?

    2. 프런트 엔드는 페이지 콘텐츠를 동기적으로 얻나요, 아니면 비동기적으로 얻나요?
    동기식인 경우 메소드는 프런트 엔드의 요구 사항을 충족할 수 없습니다.
    비동기식인 경우 쿼리 메소드는 처음으로 모든 정규화된 ID를 얻습니다(먼저 10,000개를 얻었다고 가정). 10,000 프런트 엔드에서 ID를 얻는 방법은 무엇입니까? 모두 페이지에 배치되면 프런트엔드 js는 이 배열을 사용하여 비동기 요청을 시작할 수 있지만 점프 페이지 번호가 이 범위를 초과하면 프런트엔드에서 반드시 페이지 번호 ID를 요청해야 합니다. 이번에는 쿼리를 사용해야 하는 위치

    따라서 이 계획의 현재 효과는 그리 명확하지 않습니다.
    제 분석이 맞는지는 모르겠지만 참고용으로 사용해도 됩니다.

    회신하다
    0
  • 黄舟

    黄舟2017-04-17 16:40:37

    당신의 아이디어는 ID를 프런트 엔드에 캐시하는 것이므로 ID 이외의 필드도 프런트 엔드에 캐시하는 것이 어떨까요

    예를 들어, 페이지당 50개 항목이 포함된 처음 10페이지의 데이터를 가져오려는 경우 SQL 문은 LIMIT 500을 사용하여 처음 500개 항목을 가져옵니다. 이 내에서 페이지 전환을 요청할 필요가 없습니다. 10페이지; 다음 페이지를 넘길 때까지 LIMIT 500,500의 SQL 문을 사용하여 마지막 500개 항목을 가져옵니다.

    회신하다
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-17 16:40:37

    두 가지를 조합해 시도해 볼 수 있나요? 제한 시에는 ID만 빼내고, 특정 필드는 서로 연관시킵니다.

    열 선택
       테이블 t1에서
         내부 조인 (SELECT id FROM table WHERE 조건 ORDER BY ... LIMIT m, n)t2 on t1.id=t2.id

    회신하다
    0
  • 天蓬老师

    天蓬老师2017-04-17 16:40:37

    이것은 실제로 프로젝트에 따라 다릅니다:

    1. 데이터의 양이 많고 고유한 인덱스 ID가 하나뿐이라면 나중에 제안하는 방법이 확실히 가장 빠릅니다(물론 항목 수가 너무 많아서는 안 됩니다)

    2. 색인이 생성된 다른 필드가 있고 필드의 100%를 조건으로 사용해야 하는 경우에는 물론 일반적인 ORDER BY ... LIMIT m, n 페이징 쿼리를 사용하세요. 매우 빠르다

    3. 캐싱 사용 여부는 애플리케이션 시나리오에 따라 다릅니다. 쿼리에 조건이 너무 많지 않고 데이터가 실시간으로 업데이트되지 않는 경우 사용할 수 있습니다.

    회신하다
    0
  • 취소회신하다