2013-09-01 2 views
0

У меня есть только для чтения доступ к базе данных MySQL, и мне нужно выполнить цикл через следующий запрос около 9000 раз, каждый раз с другим $ content_path_id. Я вызываю это из сценария PERL, который вытаскивает '$ content_path_id из файла.Оптимизация запроса MySQL с помощью вложенных операторов выбора?

SELECT an.uuid FROM alf_node an WHERE an.id IN 
    (SELECT anp.node_id FROM alf_node_properties anp WHERE anp.long_value IN 
     (SELECT acd.id FROM alf_content_data acd WHERE acd.content_url_id = $content_path_id)); 

Написано таким образом, он принимает навсегда сделать каждый запрос (примерно 1 минуту каждый). Я бы предпочел не ждать 9000 + минут, чтобы завершить это, если мне это не нужно. Есть ли способ ускорить этот запрос? Может быть, через соединение? Мои текущие навыки SQL смущающе ржавы ...

+0

Почему бы не иметь все '$ content_path_id' в одной таблице, соединить эту таблицу с' alf_content_data' (на 'content_url_id'), затем присоединиться к результату с помощью' alf_node_properties', а затем присоединиться к результату с помощью 'alf_node'? –

+0

'EXISTS' может быть быстрее, чем' IN'. См. Http://stackoverflow.com/questions/14190788/subqueries-with-exists-vs-in-mysql –

+0

Спасибо Nitzan. К сожалению, у меня только доступ только для чтения к БД, поэтому я не могу добавить таблицу. –

ответ

1

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

Если ваш интерфейс Perl имеет понятие подготовленных операторов, вы можете сэкономить некоторое время, подготовив один раз и выполнив 9000 различных привязок.

Вы могли бы также, возможно, сэкономить время путем создания одного запроса с большим acd.content_url_id In ($content_path_id1, $content_path_id2, ...) п

Select 
    an.uuid 
From 
    alf_node an 
     Inner Join 
    alf_node_properties anp 
     On an.id = anp.node_id 
     Inner Join 
    alf_content_data acd 
     On anp.long_value = acd.id 
Where 
    acd.content_url_id = $content_path_id 
+0

Спасибо Laurence: Это кажется несколько, но не намного, быстрее. Интересно, могу ли я сделать это быстрее, поставив все 9000 запросов как «OR» в строке «где» и выполнив его как один большой запрос. Это поможет? –

+0

Если индекс 'alf_content_data (content_url_id, acd.id) отсутствует, то он почти наверняка сделает его быстрее. Мое предложение с 'acd.content_url_id в ($ content_path_id1, ..) и т. Д. Эквивалентно этому. – Laurence

+0

Извините - я не заметил бит «acd.content_url_id In» в вашем исходном ответе. Это действительно помогло в меньшем тесте, поэтому полноразмерный работает сейчас. Благодаря! –

0

Попробуйте это расширение для решения Лоуренса, который заменяет длинный список OR-й с дополнительным JOIN:

Select 
    an.uuid 
From alf_node an 
Join alf_node_properties anp 
    On an.id = anp.node_id 
Join alf_content_data acd 
    On anp.long_value = acd.id 
Join (
    select "id1" as content_path_id union all 
    select "id2" as content_path_id union all 
    /* you get the idea */ 
    select "idN" as content_path_id 
) criteria 
    On acd.content_url_id = criteria.content_path_id 

Я использовал синтаксис SQL Server выше, но вы можете легко его перевести.

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