Требуется специальная помощь по оптимизации запросов SQL - PullRequest
0 голосов
/ 15 марта 2011

Итак, я работаю над проектом по интеллектуальному анализу данных, где мы смотрим на элементы кода, их взаимосвязи и изменения в этих вещах с течением времени.Мы хотим задать несколько вопросов о том, как часто меняются связанные элементы.Я настроил это как представление, но это занимает около 10 минут, чтобы бежать.Я полагаю, что проблема заключается в том, что мне приходится много вычитать, объединять и сравнивать строки, чтобы сравнить записи (для нашего размера окна), но я не знаю, как это исправить.Запрос выглядит как

select aw.same
     , rw.k
     , count(distint concat_ws(',', r1.id, r2.id)) as num  
  from deltamethoddeclaration dmd1
    join revision r1
      on r1.id=FKrevID 
    join methodinvocation mi
      on mi.FKcallerID = dmd1.FKMDID 
    join deltamethoddeclaration dmd2 
      on mi.FKcalleeID = dmd2.FKMDID
    join revision r2 
      on r2.id = dmd2.FKrevID
    join revisionwindow rw
    join authorwindow aw
  where (dmd1.FKrevID - dmd2.FKrevID) < rw.k
    and (dmd2.FKrevID - dmd1.FKrevID) < rw.k
    and case aw.same
          when 1 then
            r1.author = r2.author
          when 0 then
            r1.author <> r2.author
          else
            1=1
         end
  group by aw.same
         , rw.k
;

Хорошо, поэтому revisionwindow хранит интересующие нас окна ревизий (10, 20, 50, 100) и авторские окна, типы авторов которых мы хотим (одинаковые, разные и не нужные).все равно).Частично проблема заключается в том, что у нас может быть одна и та же пара ревизий с сопоставлением разных элементов, поэтому единственное, что я могу придумать, - это некрасивый счетчик (отличный от concat ()).Это должно вернуть таблицу с 12 строками, по одной для каждой комбинации окон автора и ревизии.Записи под 'num' являются уникальными парами ревизий, связанных указанным способом (в этом случае оба метода изменения и один из методов вызывают другой).Работает отлично, просто безумно медленно (~ 10 минут работы).Я в основном ищу любой совет или помощь, чтобы сделать эту работу лучше, не жертвуя точностью.

Ответы [ 2 ]

1 голос
/ 15 марта 2011
  • где (dmd1.FKrevID - dmd2.FKrevID)

    Наиболее разрушительным в этом утверждении является оператор меньше, чем < notарифметикаB-деревья не могут использовать это и вызывают полное сканирование таблицы каждый раз, в любое время.Горы подробно объясняют, почему это так: http://explainextended.com/2010/05/19/things-sql-needs-determining-range-cardinality/

  • Я сомневаюсь, что ваш оператор CASE может быть оптимизирован бэкэндом, а оператор <> страдает той же проблемой, что и выше.Я хотел бы подумать о способах объединения с операторами =, возможно, разбить запрос и использовать операторы UNION, чтобы вы всегда могли использовать индексы.

  • Вы не используете EXPLAIN.Вы должны начать использовать его для оптимизации запросов.Вы не представляете, какие индексы используются, а какие нет, или если ваше состояние достаточно избирательно, если оно будет даже полезным (если оно не очень избирательно, см. Последний пункт) http://dev.mysql.com/doc/refman/5.0/en/explain.html

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

    Я взял запросы, которые выполнялись более 60 минут, и сократил их до менее 100 мс (мгновенно), создав временные таблицы, которые кэшировали сложные вещи.Если вы не можете использовать ни одну из представленных выше идей, это, вероятно, самый низменный плод.Возьмите все «трудные вещи» - соединения с кейсами и не по равенству и сделайте это в одном месте.Затем добавьте индекс в вашу временную таблицу :-) Хитрость заключается в том, чтобы сделать его достаточно общим, чтобы вы могли запрашивать временную таблицу, чтобы у вас все еще была гибкость, чтобы задавать различные вопросы.

0 голосов
/ 15 марта 2011

Я подозреваю, что два соединения (join revisionwindow rw) и (join authorwindow aw), которые не имеют условия ВКЛ, но используют ГДЕ, вызывают это.

Сколько записей в этих двух таблицах?MySQL, вероятно, сначала выполняет CROSS JOIN, а только потом проверяет сложные (WHERE) условия.

Но, пожалуйста, опубликуйте результаты EXPLAIN.

- EDIT -
К сожалению, я пропустил ваш последний абзац, в котором объясняется, что в двух таблицах есть 4 и 3 строки.

Можете ли вы попробовать это: (где concat был заменен, а предложения where были перемещены как JOIN ON ...)

select aw.same
     , rw.k
     , count(distint r1.id, r2.id) as num  
  from deltamethoddeclaration dmd1
    join revision r1
      on r1.id = dmd1.FKrevID 
    join methodinvocation mi
      on mi.FKcallerID = dmd1.FKMDID 
    join deltamethoddeclaration dmd2 
      on mi.FKcalleeID = dmd2.FKMDID
    join revision r2 
      on r2.id = dmd2.FKrevID
    join revisionwindow rw
      on (dmd1.FKrevID - dmd2.FKrevID) < rw.k
         and (dmd2.FKrevID - dmd1.FKrevID) < rw.k
    join authorwindow aw
      on case aw.same
           when 1 then
             r1.author = r2.author
           when 0 then
             r1.author <> r2.author
           else
             1=1
          end
  group by aw.same
         , rw.k
;
...