Ответ
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
}
Важные замечания
- Производительность: На больших таблицах использование
OFFSETс большим значением может быть неэффективным, так как база данных все равно считывает, а затем отбрасывает все пропущенные строки. Для высоконагруженных систем предпочитают keyset/cursor-based pagination. - Синтаксис: Синтаксис может отличаться в разных СУБД:
- PostgreSQL/MySQL/SQLite:
LIMIT ... OFFSET ... - MS SQL Server:
OFFSET ... ROWS FETCH NEXT ... ROWS ONLY - Oracle:
OFFSET ... ROWS FETCH NEXT ... ROWS ONLY(с версии 12c) илиROWNUMв старых версиях.
- PostgreSQL/MySQL/SQLite:
Ответ 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
}
Собрал запрос, как конструктор, и поехали.
Но есть нюансы, блядь!
- Производительность — ёпта! Если у тебя таблица на миллион записей и ты делаешь
OFFSET 900000, база всё равно прочитает эти девятьсот тысяч, а потом выкинет. Это как перелопатить тонну песка, чтобы найти одну монетку. На больших объёмах и высокой нагрузке это пиздец как тормозит. Умные дяди тогда используют курсорную пагинацию (keyset/cursor-based pagination), но это уже другая история. - Синтаксис везде разный. Как эти ваши диалекты:
- PostgreSQL/MySQL/SQLite:
LIMIT ... OFFSET ...— классика. - MS SQL Server:
OFFSET ... ROWS FETCH NEXT ... ROWS ONLY— выёбистый такой. - Oracle: Там с 12c тоже
OFFSET ... ROWS FETCH NEXT ... ROWS ONLY, а в древних версиях черезROWNUMколдуют.
- PostgreSQL/MySQL/SQLite:
Вот так вот, просто и с расстановкой. Главное — не увлекайся большими оффсетами, а то сервак взвоет, как сука.