2016-12-30 6 views
2

У меня есть сложный запрос с объединением многих таблиц. Из-за сложности сложно поставить реальный запрос.Запрос SQL Server очень медленный, когда число элементов внутри раздела IN более 4

Это что-то вроде

select t1.id, t2.id, t1.name, t2.name 
from table1 t1, table2 t2 
left join table3 t3 ON t2.id = t3.id 
where t2.id = t1.ref_id 
    and t1.ref_id IN ('id1', 'id2', 'id3', 'id4', 'id5', ...) 

я обнаружил, что если у меня есть внутри В статье только 4 или меньше значения, как этого t1.ref_id IN ('id1', 'id2', 'id3', ' id4 '), он работает очень быстро (16 мс). Если я просто добавлю один id и сделаю его 5, как это t1.ref_id IN ('id1', 'id2', 'id3', 'id4', 'id5'), время выполнения увеличивается до 40 раз и становится 600 мс.

Я получил его на SQL Server 2014.

Похоже, есть некоторый параметр, который контролирует это поведение. Я пробовал этот запрос на другом SQL-сервере (SQL Server 2008), и я не мог найти никакого ограничения.

Мой вопрос: Есть ли какой-либо параметр, который контролирует такое поведение? или как увеличить этот странный предел до 50, например.

Я просто хочу увеличить его до 30-50 вместо 4. Конечно, я не хочу создавать предложение IN с сотнями и тысячами значений.

Update1

К сожалению, я забыл поставить t3.name, чтобы выбрать, в противном случае это выглядит как t3 мне не нужно:

select t1.id, t2.id, t1.name, t2.name, t3.name 
from table1 t1, table2 t2 
left join table3 t3 ON t2.id = t3.id 
where t2.id = t1.ref_id 
    and t1.ref_id IN ('id1', 'id2', 'id3', 'id4', 'id5', ...) 

UPDATE2

Похоже, я нашел причину. Проблема была не в количестве элементов внутри IN. Позже я воспроизвел этот вопрос с менее чем 4 идентификаторами (даже с 1). Это происходит, потому что некоторые идентификаторы не были представлены в t1.ref_id. когда были иды, которых нет в t1.ref_id, когда это было быстро, когда я добавил id, который существует в t1.ref_id, когда он становится медленным. В моем предыдущем примере id1 - id4 не был представлен в t1.ref_id и был представлен id5. Поэтому, когда я добавляю id5, он становится медленным. Он становится медленным, даже если я просто поставлю только 1 id (id5) внутри предложения IN. Наконец, индекс t1.ref_id решил проблему. Не было волшебства около 4 или 5 идентификаторов. Это просто совпадение в моем конкретном примере.

+0

Вы создали индекс на t1.ref_id? –

+0

Вы сделали хорошо, чтобы сузить разницу. Теперь сравните планы запросов между медленными и быстрыми версиями. Что ты видишь. Нажмите CTRL-L, чтобы просмотреть планы запросов. –

+2

Вы не должны смешивать неявный и явный синтаксис соединения, вы должны переписать на явный синтаксис. Это стандарт ANSI с 1992 года! Является ли этот запрос частью хранимой процедуры? Помогает ли это, если вы добавляете 'OPTION (RECOMPILE)'? – HoneyBadger

ответ

1

Сначала исправьте запрос. Простое правило: Никогда запятые запятые в разделе FROM.

select t1.id, t2.id, t1.name, t2.name 
from table1 t1 join 
    table2 t2 
    on t2.id = t1.ref_id left join 
    table3 t3 
    on t2.id = t3.id 
where t1.ref_id in ('id1', 'id2', 'id3', 'id4', 'id5', ...); 

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

Затем вам необходимо учитывать индексы. Я бы предложил table1(ref_id, id, name) и table2(id, name).

Также, если ref_id действительно является номером, то не ставьте одинарные кавычки вокруг значений в списке. Смешивание строк и чисел может смутить оптимизатор.

+0

Спасибо за ответ. Но я не могу изменить синтаксис разделенных запятыми таблиц в JOIN, потому что я использую некоторый продукт, где мне не разрешено напрямую изменять SQL. Таблица 3 Мне нужно, я забыл выбрать данные из него. Я изменил свой запрос в UPDATE1. ref_id - это строка. id - это вид GUID, который имеет номера и буквы, подобные этому 097777778018f16b. Индексы я бы понял, если это всегда будет медленным. но почему это быстро для 4-х и медленных для 5 идентификаторов? У меня также есть другой запрос, который выглядит аналогичным, но он берет данные из разных таблиц и имеет ту же проблему. 4 значения, если штраф, 5 медленный. – Zlelik

+1

продукт, который производит запросы со старым синтаксисом соединения? дамп, теперь – GuidoG

+0

@GuidoG Он называется «DELL EMC Documentum», и они предоставляют язык DQL (Documentum Query Language), который автоматически преобразуется в SQL с помощью Documentum Content Server. Я пишу этот DQL-запрос. Существует синтаксис LEFT join, но синтаксис JOIN отсутствует. Я попытался имитировать JOIN с LEFT JOIN, как этот LEFT JOIN table2 t2 на t2.id = t1.ref_id ... где t2.id! = '' И он работает. но он все еще имеет ту же проблему с IN. В любом случае, переписывание этого запроса с помощью соединения не будет выглядеть. Это просто борьба за красивый синтаксис :) – Zlelik

 Смежные вопросы

  • Нет связанных вопросов^_^