MySQL зміщує нескінченні рядки


114

Я хотів би побудувати запит, який відображає всі результати в таблиці, але зміщується на 5 від початку таблиці. Наскільки я можу сказати, MySQL LIMITвимагає як обмеження, так і зміщення. Чи можна це зробити?


1
Це цілком справедливе запитання, але мені цікаво, що краще було б схопити все та знехтувати перші кілька записів програмно. З огляду на жах від того, що здається найкращою відповіддю (обмеження 5, 18446744073709551615), я б дуже наполегливо працював над обмеженнями обмеження MySQL.
цезоїд

3
@cesoid, що якщо ти хочеш limit 5000, 18446744073709551615. Ви не збираєтеся отримувати зайві 5000 рядків лише для того, щоб ваш код виглядав красиво.
elipoultorak

@ user3576887 Я думаю, ти маєш рацію, я просто розглядав вищезазначене питання з припущенням, що 5 є єдиною вимогою, а не якоюсь різною сумою, яка може бути значно більшою (а не вирішенням чужої проблеми).
цезоїд

Я припускаю, що це настільки рідкісне завдання, що потворність рішення може бути прийнята.
Рік Джеймс

Відповіді:


151

З посібника MySQL від LIMIT :

Щоб отримати всі рядки від певного зміщення до кінця набору результатів, ви можете використовувати деяке велике число для другого параметра. Це твердження отримує всі рядки з 96-го ряду до останнього:

SELECT * FROM tbl LIMIT 95, 18446744073709551615;

105
Жахливо! Я прийшов сюди, сподіваючись, що MySQL зробив пункт «Обмеження» необов’язковим, як є, але також із передбаченим зміщенням ... але ні! Я бачив це розрив 18446744073709551615 по всьому коду, і я звинувачував ледачих програмістів, але це особливість дизайну!
Петруза

8
чудова відповідь, але це офіційно від MySQL Doc. Що я можу сказати @ _ @
GusDeCooL

21
18446744073709551615 - 2 ^ 64-1 для тих, хто цікавився. Ви можете стежити, тому що ви не зможете зберігати це значення в цілому 32-бітовому цілому. Ви повинні переконатися, що ви зберігаєте це як рядок, щоб забезпечити сумісність.
AlicanC

13
Страшенно! вони повинні бути витонченішими від цього ... Limit -1або Limit Nullвиглядають досить розумно! або atleast Limit повинен прийняти підзапит типуselect * from table limit (select count(*) from table)
vulcan raven

19
використовуйте php 'PHP_INT_MAX', щоб уникнути переповнення ефектів.
Карл Адлер

24

Як ви вже згадували про це, LIMIT потрібен, тому вам потрібно використовувати максимально можливий ліміт, який становить 18446744073709551615 (максимум неподписаного BIGINT)

SELECT * FROM somewhere LIMIT 18446744073709551610 OFFSET 5

33
О, це офіційне рішення від команди MySQL?
Антоній

12

Як зазначається в інших відповідях, MySQL пропонує використовувати 18446744073709551615 як кількість записів у ліміті, але врахуйте це: Що б ви зробили, якби ви отримали 18,446,744,073,709,551,615 записів? Насправді, що б ви зробили, якби отримали 1 000 000 000 записів?

Можливо, ви хочете отримати більше одного мільярда записів, але я можу сказати, що існує кількість обмежень на кількість, яку ви хочете , і це менше 18 квінтільйонів. Для стабільності, оптимізації та, можливо, зручності використання, я б запропонував поставити деякий змістовний ліміт на запит. Це також призведе до зменшення плутанини для тих, хто ніколи не бачив цього чарівного вигляду, і матиме додаткову перевагу в повідомленні хоча б того, скільки записів ви готові обробити одночасно.

Якщо ви дійсно повинні отримати всі 18 квінтільйонних записів зі своєї бази даних, можливо, ви дійсно хочете це захопити їх з кроком у 100 мільйонів і циклічно 184 мільярди разів.


Ви маєте рацію, але зберігає це рішення розробника не вибір хорошого
драми

@amd Чи можете ви пояснити це ще трохи? Я не знаю, що ти намагаєшся сказати.
цесоїд

1
@cesoid Я думаю, що він говорить, що розробникам не слід вибирати довільну логіку бізнесу, з якою я згоден, але лише до певного моменту. Скажімо, ви повертаєте список замовлень клієнту. Цілком розумно ніколи не повертати більше, ніж, скажімо, мільйон одночасно, але обмеження 100 може спричинити плутанину.
Осінній Леонард

@amd Я не кажу, що розробник повинен змінити поведінку програми, щоб уникнути використання 18446744073709551615. Я говорю, що вони повинні розглянути питання про те, чи є використання цього числа сенсом як частини впровадження будь-якого клієнта чи дизайнера інтерфейсу. просив, і дуже навряд чи це буде правильною реалізацією для чогось. Рішення про використання MySQL, ймовірно, вже прийняв розробник, не запитуючи, чи не буде більше 18 квінтільйонів чогось.
цезоїд

5

Іншим підходом було б вибрати стовпчик, що автоматично збільшується, а потім фільтрувати його за допомогою HAVING.

SET @a := 0; 
select @a:=@a + 1 AS counter, table.* FROM table 
HAVING counter > 4

Але я б, мабуть, дотримувався підходу до високої межі.


дякую, і мені цікаво, як я можу поставити такий запит у заяві PHP! я маю на увазі, що так$sql = 'SET @a :=0 SELECT .....';
Рехам Фамі

2

Як згадували інші, з посібника MySQL. Щоб досягти цього, ви можете використовувати максимальне значення безпідписаного великого int, тобто це жахливе число (18446744073709551615). Але щоб зробити його трохи менш безладно, ви можете нанести "~" побітовий оператор.

  LIMIT 95, ~0

він працює як побітове заперечення. Результат "~ ​​0" - 18446744073709551615.


1
Не працює в MariaDB 10.3 :( Я спробував і те, LIMIT 5, ~0і LIMIT ~0 OFFSET 5це функція MySQL 8.0?
jurchiks

1
Це не річ у MySQL 5.7 - недійсний синтаксис.
Джоні Нотт,

0

Щойно сьогодні я читав про найкращий спосіб отримати величезну кількість даних (понад мільйон рядків) з таблиці mysql. Один із способів - це, як було запропоновано, використання місця, LIMIT x,yде xвідбувається зміщення та yповернення останнього рядка Однак, як я з'ясував, це не найефективніший спосіб зробити це. Якщо у вас стовпець з автоматичним збільшенням, ви можете так само легко використовувати SELECTоператор з aWHERE застереженням, із якого запису ви хочете почати.

Наприклад, SELECT * FROM table_name WHERE id > x;

Здається, що mysql отримує всі результати при використанні LIMIT а потім показує лише ті записи, які відповідають зміщенню: не найкращі для продуктивності.

Джерело: Відповідь на це питання Форуми MySQL . Просто візьміть на замітку, питання про 6 років.


13
Це дасть неправильні результати, якщо ви коли-небудь видаляли запис. Цей метод є особливо небезпечним, оскільки він працює більшу частину часу, і виходить з ладу мовчки, коли цього немає.
жовтень

0

Ви можете використовувати оператор MySQL з LIMIT:

START TRANSACTION;
SET @my_offset = 5;
SET @rows = (SELECT COUNT(*) FROM my_table);
PREPARE statement FROM 'SELECT * FROM my_table LIMIT ? OFFSET ?';
EXECUTE statement USING @rows, @my_offset;
COMMIT;

Тестовано в MySQL 5.5.44. Таким чином, ми можемо уникнути вставки номера 18446744073709551615.

Примітка: транзакція гарантує, що змінна @rows узгоджується з таблицею, що розглядається при виконанні оператора.


як @amd зазначав: "Вибір підрахунку (*) на таблиці із записами 7M займає близько 17-х"
Rodrirokr

-1

Я знаю, що це старе, але я не бачив подібної відповіді, тому це рішення, яке я б використав.

По-перше, я би виконав запит підрахунку на столі, щоб побачити, скільки записів існує. Цей запит швидкий, і зазвичай час його виконання незначний. Щось на зразок:

SELECT COUNT(*) FROM table_name;

Тоді я буду будувати свій запит, використовуючи результат, отриманий від підрахунку, як мій ліміт (оскільки це максимальна кількість рядків, яку таблиця може повернути). Щось на зразок:

SELECT * FROM table_name LIMIT count_result OFFSET desired_offset;

Або можливо щось на кшталт:

SELECT * FROM table_name LIMIT desired_offset, count_result;

Звичайно, якщо потрібно, ви можете відняти бажаний зсув від count_result, щоб отримати фактичне, точне значення для подачі в якості межі. Передача значення "18446744073709551610" просто не має сенсу, якщо я дійсно можу визначити відповідний ліміт, який потрібно надати.


2
виберіть COUNT (*) на стіл з 7ми записами займає близько 17s
драми

-7
WHERE .... AND id > <YOUROFFSET>

Ідентифікатор може бути будь-яким автоматичним збільшенням або унікальним числовим стовпцем у вас ...


7
Погана ідея. Це дасть неправильне зміщення, якщо ви коли-небудь видаляли рядок.
жовтень
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.