#sql #select #where-clause #where-in
Вопрос:
Я пытаюсь сделать выбор в огромном списке с другим выбором в качестве фильтра. Я пытался выполнить следующий запрос:
DECLARE @ids TABLE (id UNIQUEIDENTIFIER PRIMARY KEY) INSERT INTO @ids SELECT TOP 1 ... -- returns D2820EDA-5F00-4EE8-A4E0-992E74D25C09 -- 0 seconds execution SELECT field1, field2, field3 FROM list WHERE id IN (SELECT id FROM @ids)
Моя проблема в том, что этот запрос занимает слишком много времени (более минуты), что в настоящее время неприемлемо.
Один и тот же запрос Select с фиксированным значением занимает около 3 секунд.
SELECT field1, field2, field3 FROM list WHERE id IN ('D2820EDA-5F00-4EE8-A4E0-992E74D25C09')
У меня одинаковое время выполнения для 100 значений фильтра.
Что я могу сделать, чтобы отфильтровать свои значения с той же скоростью, с какой я бы установил фиксированные строковые значения внутри оператора IN?
ИЗМЕНИТЬ: столбец «идентификатор» внутри «списка» не является уникальным и имеет более одного результата.
EDIT2: Я попробовал это с помощью оператора JOIN. (время выполнения даже больше, чем 2 минуты):
SELECT field1, field2, field3 FROM list AS ud JOIN @ids AS ids ON ud.id= ids.id
и со строковым результатом (время выполнения 1 минута):
DECLARE @result NVARCHAR(MAX); SELECT @result = STUFF( (SELECT TOP 1 CONVERT(VARCHAR(38), filterId) ',' FROM Filters WHERE ... FOR xml path('')) 'empty' ,1,1,''); SELECT field1, field2, field3 FROM list AS ud WHERE ',' @result LIKE '%,' CONVERT(VARCHAR(38), ud.id) ',%'
Комментарии:
1. Воспользуйся
exists
. Ваш запрос является неполным в вашем вопросе, поэтому я не могу предложить ничего большего.2. 3 секунды для одного значения-это тоже много. Есть ли у этого
id
столбца «списка» индекс?3. Я пробовал это с exists, тот же результат… в списке около 4,5 млн записей, так что 3 секунды вполне приемлемы.
4. Поскольку @ids .id является ПЕРВИЧНЫМ КЛЮЧОМ, вы также можете попробовать присоединиться.
5. @Serg это решение также работает медленно.
Ответ №1:
Есть много способов сделать то, что вы пытаетесь сделать. т. е.:
DECLARE @ids TABLE (id UNIQUEIDENTIFIER PRIMARY KEY) INSERT INTO @ids (id) values (...);
а затем запросите:
SELECT field1, field2, field3 FROM list WHERE id IN (Select id from @ids);
или:
SELECT field1, field2, field3 FROM list WHERE exists (select * from @ids i where i.id = list.id);
или:
SELECT t1.field1, t1.field2, t1.field3 FROM list t1 inner join @ids i on i.id = t1.id;
и все они будут быстрыми. Это слишком долго для вас должно быть связано с чем-то другим. Я полагаю, у вас уже есть индекс идентификатора.
Скорее всего, ваш кэшированный план запроса плох. Вы можете попробовать добавить опцию (Перекомпилировать). ie:
SELECT field1, field2, field3 FROM list WHERE id IN (Select id from @ids) Option (Recompile);
И если у вас много значений in (нужно передать тысячи идентификаторов Guid), я предлагаю использовать анализатор TVF на основе CLR, который получает их в виде значений, разделенных запятыми, и анализирует в таблице на стороне сервера.
ПРАВКА: Я не знаю, что заставило меня подумать, что это SQL server. Может быть, я видел метку другого вопроса. В любом случае, я сохраню это. Теперь я понимаю, почему я подумал о SQL server, из-за синтаксиса в ваших образцах. Весьма вероятно, что это SQL server, даже если вы не пометили свой сервер.
РЕДАКТИРОВАТЬ: Я только что протестировал это с помощью 10 ключей в таблице из 5 миллионов деталей (PartID, номер партнера, доступное количество, цена).:
DECLARE @ids TABLE(id UNIQUEIDENTIFIER); INSERT INTO @ids(id) VALUES('D5DCE10E-513C-449D-8E34-8FE771FA464A') , ('EAC65501-21F5-F831-FB07-DCFEAD50D1D9') , ('30F20823-885A-332F-86EF-B08B142F744C') , ('49849363-2487-4351-0761-57F581B71E46') , ('32502023-4B75-D650-7525-3868B79E7C31') , ('D69804D7-534E-3C43-DBAE-9F37E5E516D6') , ('8413D734-24E4-53AA-38FF-7BA6B8CF19BA') , ('55036E2E-A022-67B9-307A-8A53AB77D5CF') , ('0EC2F7C3-43B6-7002-4B85-A95549D2382F') , ('2E017358-1FE7-316B-A1ED-38ED11E6AD18'); SELECT * FROM dbo.parts AS p WHERE p.partID IN( SELECT id FROM @ids);
Прошло 18 миллисекунд.
SELECT * FROM dbo.parts AS p WHERE p.partID IN ( 'C727963F-C1B5-FE0C-1141-6B919346DF69' , 'CDBAB6F8-AB42-0DDE-51CD-AEAECAE914D7' , 'D162D88D-ABA9-FCE8-F651-B45601340B46' , '26AD28EF-846B-C4FF-281C-06F4AA958157' , '5000857A-8A0D-F500-E2C3-087443B5C60D' , '59C386F4-0412-347B-3F03-D7AB0428572D' , '0524D4A8-34A4-EA75-392A-1716DBF8A6A1' , 'F350E8A4-2F42-E21D-C308-04912065EFF8' , 'AA31FB13-FF0C-4986-9E1E-1F081028806F' , '4890072E-0B3B-E5FF-B788-FA2E2E6668AC' );
Прошло 11 миллисекунд.
Я думаю, что разница незначительна и может отличаться при повторных тестах. Попробуйте добавить ОПЦИЮ (ПЕРЕКОМПИЛЯЦИЯ).
Комментарии:
1. Да, это SQL-сервер, извините… Моя самая большая проблема заключается в том, почему он извлекает во много раз быстрее с фиксированными строковыми значениями GUID, чем с извлеченной таблицей GUID.
2. @Senad, это быстро с фиксированным или нет. С фиксированным может быть немного быстрее из-за сгенерированного плана выполнения. Вы пробовали перекомпилировать — я только что протестировал и добавил свои результаты.