MySQL смещает бесконечные строки

114

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

Stillinbeta
источник
1
Это вполне обоснованный вопрос, но мне интересно, что было бы лучше - захватить все и программно проигнорировать первые несколько записей. Учитывая ужас того, что кажется лучшим ответом (предел 5, 18446744073709551615), я бы в значительной степени предпочел обойти ограничения MySQL LIMIT.
cesoid
3
@cesoid а что, если хочешь limit 5000, 18446744073709551615. Вы не собираетесь извлекать лишние 5000 строк только для того, чтобы ваш код выглядел красиво.
elipoultorak
@ user3576887 Я думаю, что вы правы, я просто рассматривал приведенный выше вопрос с предположением, что 5 было единственным требованием, а не какой-то переменной суммой, которая может быть намного больше (и вместо решения чьей-то проблемы).
cesoid
Я предполагаю, что это настолько редкая задача, что можно смириться с безобразием решения.
Рик Джеймс

Ответы:

152

Из Руководства MySQL по LIMIT :

Чтобы получить все строки от определенного смещения до конца набора результатов, вы можете использовать большое число для второго параметра. Этот оператор извлекает все строки с 96-й до последней:

SELECT * FROM tbl LIMIT 95, 18446744073709551615;
Greg
источник
105
Ужасно! Я пришел сюда в надежде, что MySQL сделал предложение Limit необязательным, как есть, но также с предоставленным смещением ... но нет! Я видел 18446744073709551615 разброса по всему коду и обвинял ленивых программистов, но это особенность дизайна!
Петруза
8
ужасный ответ, но это официальный документ из MySQL Doc. Что я могу сказать @ _ @
GusDeCooL
21
18446744073709551615 - это 2 ^ 64-1 для тех, кому интересно. Вы можете быть осторожны, потому что вы не сможете сохранить это значение в 32-битном целом числе. Вы должны убедиться, что сохранили это как строку, чтобы обеспечить совместимость.
AlicanC
13
Ужасно! они должны быть более элегантными, чем это ... Limit -1или Limit Nullвыглядят довольно разумно! или хотя бы 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
Czimi
источник
33
Вау, это официальное решение от команды MySQL?
Энтони
12

Как отмечалось в других ответах, MySQL предлагает использовать 18446744073709551615 в качестве количества записей в пределе, но учтите следующее: что бы вы сделали, если бы получили обратно 18 446 744 073 709 551 615 записей? Фактически, что бы вы сделали, если бы у вас было 1 000 000 000 записей?

Может быть, вам действительно нужно более одного миллиарда записей, но я хочу сказать, что есть некоторый предел количества, которое вы хотите , и оно меньше 18 квинтиллионов. Ради стабильности, оптимизации и, возможно, удобства использования, я бы предложил установить некоторые значимые ограничения на запрос. Это также уменьшит путаницу для тех, кто никогда не видел это волшебное число, и получит дополнительное преимущество, сообщив, по крайней мере, сколько записей вы готовы обрабатывать одновременно.

Если вам действительно нужно получить все 18 квинтиллионов записей из вашей базы данных, возможно, вы действительно хотите получить их с шагом 100 миллионов и выполнить цикл 184 миллиарда раз.

цезоид
источник
Вы правы, но оставлять это решение разработчику - не лучший выбор
amd
@amd Не могли бы вы объяснить это поподробнее? Я не знаю, что вы пытаетесь сказать.
cesoid
1
@cesoid Я думаю, он говорит, что разработчики не должны произвольно выбирать бизнес-логику, с чем я согласен, но только до определенной степени. Допустим, вы возвращаете клиенту список заказов. Совершенно разумно никогда не возвращать больше, скажем, миллиона за раз, но ограничение до 100 может вызвать путаницу.
Осенний Леонард
@amd Я не говорю, что разработчик должен изменить поведение приложения, чтобы избежать использования 18446744073709551615. Я говорю, что им следует подумать о том, имеет ли смысл использовать это число как часть реализации того, что клиент или дизайнер интерфейса запросил, и вряд ли это будет правильная реализация для чего-либо. Решение использовать MySQL, вероятно, уже было принято разработчиком, не задавая вопросов, будет ли что-то более 18 квинтиллионов.
cesoid
5

Другой подход - выбрать столбец с автоимкрементом и затем отфильтровать его с помощью HAVING.

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

Но я бы, вероятно, придерживался подхода высоких лимитов.

Jishi
источник
спасибо, и мне интересно, как я могу поместить такой запрос в оператор PHP! Я имею в виду, что так$sql = 'SET @a :=0 SELECT .....';
Рехам Фахми
2

Как уже упоминалось, из руководства MySQL. Чтобы достичь этого, вы можете использовать максимальное значение беззнакового большого int, то есть это ужасное число (18446744073709551615). Но чтобы сделать его немного менее беспорядочным, вы можете использовать побитовый оператор тильды "~".

  LIMIT 95, ~0

он работает как побитовое отрицание. Результат «~ 0»: 18446744073709551615.

Bruno.S
источник
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оператор с WHEREпредложением, говорящим, с какой записи вы хотите начать.

Например, SELECT * FROM table_name WHERE id > x;

Кажется, что mysql получает все результаты, когда вы используете, LIMITа затем показывает вам только записи, которые соответствуют смещению: не лучший для производительности.

Источник: ответ на этот вопрос Форумы MySQL . Сразу заметьте, вопрос примерно 6 лет.

кормили
источник
13
Это даст неверные результаты, если вы когда-либо удаляли запись. Этот метод особенно опасен, потому что он работает большую часть времени и тихо дает сбой, когда он не работает.
octern
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 соответствует таблице, учитываемой при выполнении оператора.

sissi_luaty
источник
как указано в @amd: «select count (*) в таблице с 7M записями занимает около 17
секунд
-1

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

Сначала я бы выполнил запрос количества в таблице, чтобы увидеть, сколько записей существует. Этот запрос выполняется быстро и обычно время выполнения незначительно. Что-то вроде:

SELECT COUNT(*) FROM table_name;

Затем я бы построил свой запрос, используя результат, который я получил от count, как свой предел (поскольку это максимальное количество строк, которое таблица могла бы вернуть). Что-то вроде:

SELECT * FROM table_name LIMIT count_result OFFSET desired_offset;

Или, возможно, что-то вроде:

SELECT * FROM table_name LIMIT desired_offset, count_result;

Конечно, при необходимости вы можете вычесть желаемое смещение из count_result, чтобы получить фактическое точное значение, которое будет использоваться в качестве ограничения. Передача значения «18446744073709551610» просто не имеет смысла, если я действительно могу определить подходящий предел для предоставления.

Барон фон Спарклфартс
источник
2
select count (*) в таблице с 7M записями занимает около 17
amd
-7
WHERE .... AND id > <YOUROFFSET>

id может быть любым автоматически увеличивающимся или уникальным числовым столбцом, который у вас есть ...

user3131125
источник
7
Плохая идея. Это даст неправильное смещение, если вы когда-либо удаляли строку.
octern