Что такое `LIMIT` в SQL и как его использовать для пагинации?

Ответ

LIMIT — это SQL-оператор, который ограничивает количество строк, возвращаемых запросом. Это один из ключевых инструментов для реализации пагинации (постраничного вывода данных).

Использование для пагинации

Для пагинации LIMIT почти всегда используется в паре с оператором OFFSET, который указывает, сколько строк нужно пропустить от начала выборки.

  • LIMIT N: Вернуть первые N строк.
  • LIMIT N OFFSET M: Пропустить M строк и вернуть следующие N строк.

Например, чтобы показать 20 записей на 3-й странице: OFFSET = (3 - 1) * 20 = 40 LIMIT = 20

SELECT * FROM products ORDER BY created_at DESC LIMIT 20 OFFSET 40;

Пример на Go (GORM)

В Go ORM, таких как GORM, для этого есть удобные методы .Limit() и .Offset().

package main

import (
    "gorm.io/gorm"
)

type User struct {
    ID   uint
    Name string
}

func GetUsersPage(db *gorm.DB, page, pageSize int) ([]User, error) {
    var users []User

    offset := (page - 1) * pageSize

    // SELECT * FROM users LIMIT pageSize OFFSET offset;
    result := db.Limit(pageSize).Offset(offset).Find(&users)

    return users, result.Error
}

Важные замечания

  1. Производительность: На больших таблицах использование OFFSET с большим значением может быть неэффективным, так как база данных все равно считывает, а затем отбрасывает все пропущенные строки. Для высоконагруженных систем предпочитают keyset/cursor-based pagination.
  2. Синтаксис: Синтаксис может отличаться в разных СУБД:
    • PostgreSQL/MySQL/SQLite: LIMIT ... OFFSET ...
    • MS SQL Server: OFFSET ... ROWS FETCH NEXT ... ROWS ONLY
    • Oracle: OFFSET ... ROWS FETCH NEXT ... ROWS ONLY (с версии 12c) или ROWNUM в старых версиях.

Ответ 18+ 🔞

Смотри, вот тебе про этот ваш LIMIT, чтоб ты понимал, как с ним работать, а то некоторые думают, что это какая-то магия, а не обычный инструмент.

Этот оператор — он как шлагбаум, блядь. Стоит на дороге из базы данных и говорит: «Всё, мужики, дальше ни ногой! Только первые N машин проезжают». Основная его работа — пагинация, то есть постраничный вывод, чтобы не вываливать пользователю десять тысяч записей разом, а то он с ума сойдёт.

Для пагинации LIMIT всегда таскает с собой своего кореша — OFFSET. Это такой тип, который командует: «Эй, первые M записей — отдыхайте, мы вас не берём. А вот следующие N — поехали».

  • LIMIT 10 — дай мне десять штук с самого начала.
  • LIMIT 10 OFFSET 20 — первые двадцать пропусти нахуй, а следующие десять — мои.

Допустим, у тесть на странице 20 товаров, а ты хочешь показать третью страницу. Считаем: OFFSET = (3 - 1) * 20 = 40. LIMIT = 20.

SELECT * FROM products ORDER BY created_at DESC LIMIT 20 OFFSET 40;

Вот и вся математика, епта. Не космос.

Как это в Go (GORM) выглядит

Тут вообще красота, методы .Limit() и .Offset() делают всю грязную работу.

package main

import (
    "gorm.io/gorm"
)

type User struct {
    ID   uint
    Name string
}

func GetUsersPage(db *gorm.DB, page, pageSize int) ([]User, error) {
    var users []User

    offset := (page - 1) * pageSize

    // SELECT * FROM users LIMIT pageSize OFFSET offset;
    result := db.Limit(pageSize).Offset(offset).Find(&users)

    return users, result.Error
}

Собрал запрос, как конструктор, и поехали.

Но есть нюансы, блядь!

  1. Производительность — ёпта! Если у тебя таблица на миллион записей и ты делаешь OFFSET 900000, база всё равно прочитает эти девятьсот тысяч, а потом выкинет. Это как перелопатить тонну песка, чтобы найти одну монетку. На больших объёмах и высокой нагрузке это пиздец как тормозит. Умные дяди тогда используют курсорную пагинацию (keyset/cursor-based pagination), но это уже другая история.
  2. Синтаксис везде разный. Как эти ваши диалекты:
    • PostgreSQL/MySQL/SQLite: LIMIT ... OFFSET ... — классика.
    • MS SQL Server: OFFSET ... ROWS FETCH NEXT ... ROWS ONLY — выёбистый такой.
    • Oracle: Там с 12c тоже OFFSET ... ROWS FETCH NEXT ... ROWS ONLY, а в древних версиях через ROWNUM колдуют.

Вот так вот, просто и с расстановкой. Главное — не увлекайся большими оффсетами, а то сервак взвоет, как сука.