MySQL количество элементов в «в предложении» - PullRequest
61 голосов
/ 07 октября 2009

У меня есть три таблицы для определения пользователей:

USER: user_id (int), username (varchar)
USER_METADATA_FIELD: user_metadata_field_id (int), field_name (varchar)
USER_METADATA: user_metadata_field_id (int), user_id (int), field_value (varchar)

Я хотел бы создать пользователя среднего уровня, который имеет определенный доступ к другим пользователям в приложении. Чтобы определить, какие пользователи могут войти в систему, я использую подзапрос, подобный следующему:

SELECT user_id FROM user WHERE user_id 
     IN (SELECT user_id 
         FROM user_metadata 
         WHERE user_metadata_field_id = 1 AND field_value = 'foo')

В настоящее время я сохраняю строку подзапроса в переменной, а затем динамически вставляю ее во внешний запрос каждый раз, когда мне нужно получить список пользователей. После этого я подумал: «Должно быть, лучше просто хранить строку фактических user_id s».

Так что вместо того, чтобы хранить это в переменной ...

$subSql = "SELECT user_id FROM user_metadata WHERE user_metadata_field_id = 1 AND field_value = 'foo'";

... Я на самом деле выполняю запрос и сохраняю результат следующим образом ...

$subSql = "12, 56, 89, 100, 1234, 890";

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

$sql = "SELECT user_id FROM user WHERE user_id IN ($subSql)";

И, наконец, вопросы:

Сколько предметов вы можете использовать в MySQL IN CLAUSE? Хранение фактических идентификаторов вместо оператора sub-sql должно быть быстрее для выполнения этого внешнего запроса каждый раз, верно?

Ответы [ 4 ]

149 голосов
/ 10 января 2012

Из руководства :

Количество значений в списке IN ограничено только значением max_allowed_packet.

34 голосов
/ 07 октября 2009

Начиная с определенного числа, таблицы IN быстрее.

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

См. Эту статью в моем блоге для деталей производительности:

11 голосов
/ 07 октября 2009

Как указывалось в ответе Quassnoi, один натыкается на другие практические соображения, до достижения любого возможного предела , налагаемого реализацией данной версии MySql (*). Следовательно, по мере роста числа пользователей-администраторов (или других критериев, которым может потребоваться конструкция IN), следует стремиться использовать альтернативы буквальному «IN», такие как использование временных (или даже постоянных) таблиц.

Поскольку вы рассматриваете возможность специальной обработки критериев «пользователь-администратор», для повышения производительности я хотел бы предложить комментарий и предложение.

Комментарий: Может ли это быть случаем преждевременной оптимизации?
Я не знаю специфики этой базы данных, ее объема, сложности и т. Д. И, да, мне известны некоторые данные о производительности, которые должны быть уплачены в формате EAV (Entity-Attribute-Value), но я думаю, что даже для успешного бизнеса база данных учетных записей редко насчитывает более 10 000 пользователей. Поэтому, даже имея очень много атрибутов на пользователя, мы по-прежнему смотрим на сравнительно небольшую таблицу EAV, которая может не требовать такого типа оптимизации. (С другой стороны, некоторые другие приемы оптимизации могут приветствоваться в других областях.)
Кроме того, типичные варианты использования включают относительно небольшое количество запросов в базу данных учетных записей по сравнению с другими запросами, и, следовательно, это еще одна причина, по которой следует задерживать любое нетривиальное рассмотрение производительности для связанных с учетными записями функций приложения.

Предложение: Может быть, использовать "повторно нормализованные атрибуты"
Для атрибутов с одиночным значением и, в частности, если они короткие, их можно переместить (или дублировать) в таблицу сущностей (в данном случае таблицу «USER»). Это вводит некоторую логику во время вставки или обновления элементов, но это совпадает со многими объединениями (или подзапросами), а также предоставляет возможность учитывать многопольные индексы для поддержки наиболее распространенных вариантов использования.

(*) Есть ли предел?
Я не читал ни о каком таком ограничении; Я знаю, что у Oracle был (был) предел в 1000 раз, а MSSQL - нет; конечно, все серверы имеют ограничение, основанное на общей длине оператора SQL, но это действительно большое число! если кто-то наткнется на него, у него / нее будут другие проблемы ... ;-)

7 голосов
/ 20 апреля 2011

В предложении MySQL нет такого ограничения. Я попробовал с 8000 элементов, он отлично работает для меня. Ошибка переполнения стека может быть объявлена ​​переменной,

...