2014-02-11 3 views
0

У меня есть запрос ниже, я пытаюсь переписать его для повышения производительности, какой подход я могу использовать для его перезаписи.Как переписать запрос MySQL

select 
    notes.id, notes.name, notes.parent_type, notes.contact_id from notes 
JOIN 
    ( 
    SELECT contact_id as id from accounts_contacts where account_id = 'acct1876' and deleted = '0' union 
    SELECT quote_id as id from quotes_accounts where account_id = 'acct1876' and deleted = '0' union 
    SELECT opportunity_id as id from accounts_opportunities where account_id = 'acct1876' and deleted = '0' union 
    SELECT leads.id as id from leads where account_id = 'acct1876' and deleted = '0' union 
    SELECT project_id as id from projects_accounts where account_id = 'acct1876' and deleted = '0' union 
    select 'acct1876' as id 
    ) A 
    ON A.id = notes.parent_id and deleted = '0' OR contact_id in 
    (SELECT contact_id from accounts_contacts where account_id = 'acct1876' and deleted = '0') and deleted = '0' 

    group by notes.id; 
+0

Вы можете узнать о JOINs, но действительно непонятно, что вы на самом деле пытаетесь сделать здесь!?!?! – Strawberry

+3

Это могло бы помочь вам, если бы вы могли объяснить свое требование, а не надеяться, что люди на SO будут правильно перепроектировать его из вашего запроса.Кроме того, вы злоупотребляете «GROUP BY»; в вашем запросе нет агрегирующих функций (таких как 'SUM()' или 'GROUP_CONCAT()'). –

+0

В основном запрос выполняется медленно. Индексирование в порядке, но по всей производительности это не очень хорошо. Я пытаюсь реструктурировать запрос для получения того же результата. –

ответ

0

Чтобы ответить на ваш вопрос И повысить производительность, я хотел бы предложить подход, который может показаться странным с первого взгляда.

Если у вас есть разумное количество записей, используйте БОЛЬШЕ ВЫБОРОВ, а не один (и тяжелый). Вы можете собирать идентификаторы в массиве или (предпочтительно) в строке, а затем делать другой запрос с идентификационным списком, разделенным запятыми и т. Д. Это (хотя это звучит полная бессмыслица) имеет много преимуществ и практически никаких недостатков: отдельные SELECT работают быстро , затем дайте db-серверу дышать. Когда вы делаете один SELECT, другие таблицы не будут заблокированы (!!!), в то время как один большой выбор блокирует ВСЕ таблицы, задействованные в течение всего времени запроса. Так что проще и более удобным для чтения, чтобы сделать это:

$idlist = fetch_idlist("select id from users where name like 'John%'"); 
$result = fetch_all("select * from mails where userid in ($idlist)"); 

, чем это:

$result = fetch_all("select * from mails left join users on users.id=mails.userid ....") 

Я надеюсь, что смысл понятен, несмотря на несуществующих функций. Это только принцип. Таким образом, в вашем случае, возможно, вы хотите выбрать контакты, создать список идентификаторов, затем сделать отдельный запрос для заметок и т. Д. И составить окончательный результат в php.

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

Извините, если это не 100% ответа, но я подумал, что это стоит объяснить.

1

Во-первых, ваш последний OR является дубликатом начала вашего внутреннего соединения и, в противном случае, бессмысленным.

Эта часть

ON A.id = notes.parent_id 
    and deleted = '0' 
    OR contact_id in (SELECT contact_id 
         from accounts_contacts 
         where account_id = 'acct1876' 
         and deleted = '0') 
    and deleted = '0' 

может быть просто

ON A.id = notes.parent_id 

Далее, оказывается, вы пытаетесь получить все идентификаторы, связанные с данной учетной записью, в том числе счета в вопросе. Я бы удостоверился, что каждая из этих таблиц имеет индекс в идентификаторах учетной записи и удаленных столбцах. Кроме того, для этого запроса у меня было бы DISTINCT, чтобы исключить дубликаты, связанные с таблицей заметок. Затем я заменил бы заказ (для меня, мысленно запросите идентификаторы, которые вы хотите, ТОГДА получите связанные записи). Ниже приведены индексы для каждой таблицы вашего запроса UNION, а также таблица заметок по столбцу объединенного родительского идентификатора.

table     index 
accounts_contacts  (account_id, deleted, contact_id) 
quotes_accounts  (account_id, deleted, quote_id) 
accounts_opportunities (account_id, deleted, opportunity_id) 
leads     (account_id, deleted, id 
projects_accounts  (account_id, deleted, project_id) 
notes     (parent_id) 

Теперь несовершеннолетнего обновленного запрос

select 
     notes.id, 
     notes.name, 
     notes.parent_type, 
     notes.contact_id 
    from 
     (SELECT DISTINCT contact_id as id 
      from accounts_contacts 
      where account_id = 'acct1876' and deleted = '0' 
      union 
      SELECT quote_id as id 
      from quotes_accounts 
      where account_id = 'acct1876' and deleted = '0' 
      union 
      SELECT opportunity_id as id 
      from accounts_opportunities 
      where account_id = 'acct1876' and deleted = '0' 
      union 
      SELECT leads.id as id 
      from leads 
      where account_id = 'acct1876' and deleted = '0' 
      union 
      SELECT project_id as id 
      from projects_accounts 
      where account_id = 'acct1876' and deleted = '0' 
      union 
      select 'acct1876' as id) A 
     JOIN Notes 
      ON A.id = notes.parent_id 
    group by 
    notes.id; 

Как один отметил, что у вас есть группа по, но не сумма или агрегата на колоннах, которые приведут к первой записи, найденной для такого быть и, поскольку на том, что появляется столбец с автоинкрементами, будет иметь то же значение независимо от того, откуда возникла учетная запись «ИД».

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