Медленный SQL-запрос - не могу найти - PullRequest
0 голосов
/ 05 марта 2012

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

# Mon Mar  5 11:00:00 2012
# Query_time: 4.028706  Lock_time: 0.000272 Rows_sent: 15  Rows_examined: 12188513 use futureg2_imbc; 

SELECT uploadsNew.id   ,
    uploadsNew.title   , uploadsNew.genre   , uploadsNew.content   ,
    uploadsNew.url   , uploadsNew.approved, (IF(v.views IS NOT NULL,
    v.views, 0) + IF(vc.old_views IS NOT NULL, vc.old_views, 0)) AS views,
    r.likes   , r.dislikes FROM uploadsNew   
  LEFT JOIN    
    (SELECT id   ,
      COUNT(*) AS views   
     FROM views   
    WHERE type = '0' AND subtype = '1'  
    GROUP BY id   
    ) AS v   
  ON v.id = uploadsNew.id   
  LEFT JOIN   
    (SELECT
      id   , SUM(views) AS old_views   
    FROM viewsCondensed   
    WHERE type = '0' AND subtype = '1'   
    GROUP BY id   
    ) AS vc   
  ON vc.id = uploadsNew.id   
  LEFT JOIN   
    (SELECT upload   , SUM(IF(rating = '1', 1, 0)) AS likes   , 
      SUM(IF(rating = '-1', 1, 0)) AS dislikes   ,
      IF(username = '', rating, 0) AS user_rated   
    FROM ratingNew   
    WHERE ratingNew.type = '0'   
    GROUP BY upload ) AS r   
  ON r.upload = uploadsNew.id   
  WHERE uploadsNew.type = '1'   AND uploadsNew.status ='0'   AND 
    uploadsNew.school = 'illinois-state-university'   
GROUP BY
  uploadsNew.id ORDER BY uploadsNew.approved DESC LIMIT 15

ДАЖЕ НЕ МОЖЕТ ИСПОЛЬЗОВАТЬ НА МОЕЙ СТРАНИЦЕ. Даже после того, как я каждый раз изменяю свой код и смотрю на него 100 раз, это все еще остается проблемой, и это тот же самый код, запускаемый несколько раз в секунду, каждый раз, когда они блокируют мою учетную запись.

Вот код PHP:

$sql = "SELECT uploadsNew.id
    , uploadsNew.title
    , uploadsNew.genre
    , uploadsNew.content
    , uploadsNew.url
    , uploadsNew.approved";
if($type < 3) $sql .= ", (IF(v.views IS NOT NULL, v.views, 0) + IF(vc.old_views IS NOT NULL, vc.old_views, 0)) AS views";
else $sql .= ", uploadsNew.member
    , uploadsNew.anonymous
    , r.ratedSong";
$sql .= ", r.likes
    , r.dislikes";
if($sort == "rated") $sql .= ", (r.likes - r.dislikes) AS rating";
if(isset($school)) $sql .= ", s.school_id";
$sql .= " FROM uploadsNew";
if(isset($school)) $sql .= " LEFT JOIN (SELECT url, id AS school_id FROM schools) AS s ON s.url = '". $school ."'";
$sql .= " LEFT JOIN 
            (SELECT id
                , COUNT(*) AS views
            FROM views
            WHERE type = '0' AND subtype = '". $type ."'
            GROUP BY id
            ) AS v
            ON v.id = uploadsNew.id
        LEFT JOIN
            (SELECT id
                , SUM(views) AS old_views
            FROM viewsCondensed
            WHERE type = '0' AND subtype = '". $type ."'
            GROUP BY id
            ) AS vc
            ON vc.id = uploadsNew.id
        LEFT JOIN
            (SELECT upload
                , SUM(IF(rating = '1', 1, 0)) AS likes
                , SUM(IF(rating = '-1', 1, 0)) AS dislikes
                , IF(username = '". $user['username'] ."', rating, 0) AS user_rated
            FROM ratingNew
            WHERE ratingNew.type = '0'
            GROUP BY upload
            ) AS r
            ON r.upload = uploadsNew.id
        WHERE uploadsNew.type = '". $type ."' AND uploadsNew.status = '0'";
if($genre) $sql .= " AND uploadsNew.genre = '". strtolower($genre) ."'";
if(isset($school)) $sql .= " AND uploadsNew.school = s.school_id";
else $sql .= $filter;
$sql .= " GROUP BY uploadsNew.id ORDER BY ". $s ." LIMIT ". ($page - 1) * $limit .", ". $limit;

Если кто-нибудь может даже понять, как приведенный выше код может даже выполняться из этого единственного запроса - не стесняйтесь. Также, если вы сможете понять, КАК он запускается несколько раз в секунду (как если бы он был зациклен), я бы полюбил вас еще больше.

Кроме того, эффективен ли вышеуказанный подход? У меня была другая ветка по этому поводу (ну, в общем, база данных), и никто никогда не отвечал на мой вопрос.

Поддержка оказывает мне небольшую помощь и продолжает ссылаться на очевидные вещи, на которые можно смотреть. Я чувствую, что самая большая вещь, так как таблица viewsCondensed примерно примерно 80 тысяч штук.

В основном таблица viewsCondensed используется для сжатия ежедневных просмотров всего (в таблице views) до полностью дневной суммы (viewsCondensed).

Должен ли я просто изменить это на еженедельную или ежемесячную вещь? Раньше все это было частью таблицы uploadsNew, хотя я чувствовал, что это несколько неэффективно и не позволяет сохранять фактические данные ежедневно.

ЛЮБАЯ И ВСЕ ПОМОЩЬ БУДЕТ ОЧЕНЬ ЦЕННЫМ!


Извините, здесь больше данных с EXPLAIN для SELECT, а также для различных таблиц:

Это НОРМАЛЬНЫЙ запрос, который запускается на странице, на которой «запускается» предыдущий:

SELECT uploadsNew.id
  , uploadsNew.title
  , uploadsNew.genre
  , uploadsNew.content
  , uploadsNew.url
  , uploadsNew.approved, (IF(v.views IS NOT NULL, v.views, 0) + IF(vc.old_views IS NOT NULL, vc.old_views, 0)) AS views, r.likes
  , r.dislikes FROM uploadsNew
  LEFT JOIN 
  (SELECT id
  , COUNT(*) AS views
  FROM views
  WHERE type = '0' AND subtype = '1'
  GROUP BY id
  ) AS v
  ON v.id = uploadsNew.id
  LEFT JOIN
  (SELECT id
  , SUM(views) AS old_views
  FROM viewsCondensed
  WHERE type = '0' AND subtype = '1'
  GROUP BY id
  ) AS vc
  ON vc.id = uploadsNew.id
  LEFT JOIN
  (SELECT upload
  , SUM(IF(rating = '1', 1, 0)) AS likes
  , SUM(IF(rating = '-1', 1, 0)) AS dislikes
  , IF(username = '', rating, 0) AS user_rated
  FROM ratingNew
  WHERE ratingNew.type = '0'
  GROUP BY upload
  ) AS r
  ON r.upload = uploadsNew.id
  WHERE uploadsNew.type = '1'
  AND uploadsNew.status = '0'
  GROUP BY uploadsNew.id ORDER BY uploadsNew.approved DESC LIMIT 15

Объясните выше:

1 PRIMARY uploadsNew     ref type,type_2               type_2 8 const,const 1965 Using temporary; Using filesort
1 PRIMARY <derived2>     ALL NULL                      NULL   NULL NULL     1335
1 PRIMARY <derived3>     ALL NULL                      NULL   NULL NULL     5429
1 PRIMARY <derived4>     ALL NULL                      NULL   NULL NULL      372
4 DERIVED ratingNew      ALL NULL                      NULL   NULL NULL     2111 Using where; Using temporary; Using filesort
3 DERIVED viewsCondensed ref type,type_2,type_3,type_4 type_2 8            67475 Using where; Using temporary; Using filesort
2 DERIVED views        index type                      id_2   12   NULL     4351 Using where; Using index

Объясните начальный «проблемный» запрос:

1 ПЕРВИЧНЫЕ закачкиНовый тип ссылки, type_2 type_2 8 const, const 1896 Использование где; Используя временные; Использование сортировки файлов 1 ПЕРВИЧНЫЙ ВСЕ НУЛЬ НУЛЬ НУЛЬ НУЛЬ 479 1 ПЕРВИЧНЫЙ ВСЕ НУЛЬ НУЛЬ НУЛЬ НУЛЬ 6015
1 ПЕРВИЧНЫЙ ВСЕ НУЛЬ НУЛЬ НУЛЬ НУЛЬ 384 4 ПРОИЗВЕДЕННАЯ оценкаNew ВСЕ НУЛЬ НУЛ НУЛЬ НУЛЬ 2171 Использование где; С помощью временный; Использование сортировки файлов 3 ПРОИЗВОДНЫХ просмотровСконцентрированный тип ссылки, тип_2, тип_3, тип_4 тип_3 4 53779 Использование где; Используя временные; Использование сортировки файлов 2 ПРОИЗВОДНЫЕ просмотров ref type type 4 688 Using where; Используя временные; Использование сортировки файлов

таблица просмотров:

CREATE TABLE views (id int (10) NOT NULL ПО УМОЛЧАНИЮ '0', type int (1) NOT NULL DEFAULT '0', subtype int (1) NOT NULL DEFAULT '0', date datetime NOT NULL, ip int (20) NOT NULL ПО УМОЛЧАНИЮ '0', user varchar (20) NOT NULL, КЛЮЧ id (id, type), КЛЮЧ id_2 (id, type, subtype), КЛЮЧ id_3 (id, type, date), КЛЮЧ type (type, ip)) ДВИГАТЕЛЬ = CHISSET ПО УМОЛЧАНИЮ MyISAM = latin1

viewsCdensed table:

CREATE TABLE viewsCondensed (id int (10) NOT NULL ПО УМОЛЧАНИЮ '0', type int (1) NOT NULL ПО УМОЛЧАНИЮ '0', subtype int (1) NOT NULL ПО УМОЛЧАНИЮ '0', date дата NOT NULL, views int (10) NOT NULL ПО УМОЛЧАНИЮ '0', КЛЮЧ id (id, type), КЛЮЧ id_2 (id, type, subtype), КЛЮЧ id_3 (id, type, date), КЛЮЧ type (type, views), КЛЮЧ type_2 (type, subtype, views), КЛЮЧ type_3 (type, date, views), КЛЮЧ type_4 (type)) ДВИГАТЕЛЬ = CHISSET ПО УМОЛЧАНИЮ MyISAM = latin1

uploadsNew table:

CREATE TABLE uploadsNew (id int (10) NOT NULL AUTO_INCREMENT, member varchar (30) NOT NULL, ip int (20) NOT NULL, gallery varchar (30) NOT NULL, type int (1) NOT NULL, genre varchar (30) NOT NULL, anonymous int (1) NOT NULL, school int (6) NOT NULL, added datetime NOT NULL, approved datetime NOT NULL, title varchar (255) NOT NULL, content varchar (2500) NOT NULL, url varchar (300) NOTNULL, address varchar (40) NOT NULL, tags varchar (200) NOT NULL, rating int (1) NOT NULL, status int (1) NOT NULL, source varchar (600) NOT NULL, первичный ключ (id), ключ id (id, member, status), КЛЮЧ type (type, genre, approved, rating, status), КЛЮЧ type_2 (type, status)) ДВИГАТЕЛЬ = MyISAM AUTO_INCREMENT = 6004 ПО УМОЛЧАНИЮ CHARSET = latin1

рейтингНовая таблица:

CREATE TABLE ratingNew (upload int (10) NOT NULL, type int (1) NOT NULL ПО УМОЛЧАНИЮ '0', username varchar (20) NOT NULL, ip int (16) NOT NULL, rating int (1) NOT NULL, date datetime NOT NULL, KEY upload (upload, type)) ENGINE = MySAM CHARSET DEFAULT = latin1


Больше правок (пробовал новый запрос и объяснял):

новый запрос

SELECT 
    uploadsNew.id,     uploadsNew.title, 
    uploadsNew.genre,  uploadsNew.content,
    uploadsNew.url,    uploadsNew.approved, 
    COALESCE(v.views, 0) + COALESCE(vc.old_views, 0) AS views,
    r.likes,           r.dislikes 
FROM  ( SELECT *
        FROM uploadsNew
        WHERE type = 1  
          AND status = 0  
        ORDER BY approved DESC 
        LIMIT 15
      ) AS uploadsNew  
  LEFT JOIN    
      ( SELECT  id,  COUNT(*) AS views   
        FROM views   
        WHERE type = 0 AND subtype = 1  
        GROUP BY id   
      ) AS v   ON v.id = uploadsNew.id   
  LEFT JOIN   
      ( SELECT  id,  SUM(views) AS old_views   
        FROM viewsCondensed   
        WHERE type = 0 AND subtype = 1   
        GROUP BY id   
      ) AS vc  ON vc.id = uploadsNew.id   
  LEFT JOIN   
      ( SELECT  upload, 
                SUM(rating = 1 ) AS likes, 
                SUM(rating = -1) AS dislikes,
                IF(username = '', rating, 0) AS user_rated   
        FROM ratingNew   
        WHERE type = 0   
        GROUP BY upload 
      ) AS r   ON r.upload = uploadsNew.id   
ORDER BY uploadsNew.approved DESC 

Объяснение

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   PRIMARY <derived2>  ALL NULL    NULL    NULL    NULL    15  Using temporary; Using filesort
1   PRIMARY <derived3>  ALL NULL    NULL    NULL    NULL    479 
1   PRIMARY <derived4>  ALL NULL    NULL    NULL    NULL    6015    
1   PRIMARY <derived5>  ALL NULL    NULL    NULL    NULL    384 
5   DERIVED ratingNew   index   NULL    upload_3    34  NULL    2171    Using where; Using index
4   DERIVED viewsCondensed  ref type,type_2,type_3,type_4   type_3  4       53779   Using where; Using temporary; Using filesort
3   DERIVED views   ref type    type    4       688 Using where; Using temporary; Using filesort
2   DERIVED uploadsNew  range   type,type_2,type_3,type_4   type_4  4   NULL    5970    Using where

Ответы [ 2 ]

6 голосов
/ 06 марта 2012
  1. Что такое PRIMARY KEY из uploadsNew?Это id?Если да, удалите GROUP BY uploadsNew.id.Он должен давать идентичные результаты.

  2. Какие показатели у вас есть в таблицах?Если нет, добавьте:

    • индекс на (type, subtype, id) в таблице views
    • индекс на (type, subtype, id, views) в таблице viewsCondensed.
    • индекс по (type, upload, rating) в таблице ratingNew.
    • индекс по (type, status, school, approved) в таблице uploadsNew.
  3. Тогда, (пока не выполняйте запрос), но используйте оператор EXPLAIN, чтобы получить план запроса и опубликовать его здесь.Также было бы хорошо, если бы вы добавили определения таблиц (поэтому мы знаем типы данных и индексы, которые у вас есть).

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

  5. У вас есть несколькоизбыточные индексы, но это не является причиной низкой производительности вышеупомянутых запросов, поэтому давайте пропустим это тоже (но вы должны позаботиться об этом и через некоторое время).

  6. Добавьте индексы, которые я поместил в комментарии 2 выше.Единственный, кто не может быть лучшим - это (type, upload, rating) в таблице ratingNew.Вместо этого это может быть: (type, upload, username, rating), но если в этой таблице не так много строк, это не будет проблемой.

  7. Ваш код создает несколько вариантов запроса.Таким образом, вам также нужно добавить этот индекс: (type, status, approved) в таблицу uploadsNew.

Затем попробуйте сначала объяснить это изменение, а затем запустите его:

SELECT 
    uploadsNew.id,     uploadsNew.title, 
    uploadsNew.genre,  uploadsNew.content,
    uploadsNew.url,    uploadsNew.approved, 
    COALESCE(v.views, 0) + COALESCE(vc.old_views, 0) AS views,
    r.likes,           r.dislikes 
FROM  ( SELECT *
        FROM uploadsNew
        WHERE type = 1  
          AND status = 0  
          AND school = 'illinois-state-university'   
        ORDER BY approved DESC 
        LIMIT 15
      ) AS uploadsNew  
  LEFT JOIN    
      ( SELECT  id,  COUNT(*) AS views   
        FROM views   
        WHERE type = 0 AND subtype = 1  
        GROUP BY id   
      ) AS v   ON v.id = uploadsNew.id   
  LEFT JOIN   
      ( SELECT  id,  SUM(views) AS old_views   
        FROM viewsCondensed   
        WHERE type = 0 AND subtype = 1   
        GROUP BY id   
      ) AS vc  ON vc.id = uploadsNew.id   
  LEFT JOIN   
      ( SELECT  upload, 
                SUM(rating = 1 ) AS likes, 
                SUM(rating = -1) AS dislikes,
                IF(username = '', rating, 0) AS user_rated   
        FROM ratingNew   
        WHERE type = 0   
        GROUP BY upload 
      ) AS r   ON r.upload = uploadsNew.id   
ORDER BY uploadsNew.approved DESC 
0 голосов
/ 05 марта 2012

Вы никогда не должны использовать подвыборки, вместо этого переформатируйте их, чтобы использовать их так же, как стандартное левое соединение.

Мне трудно разобрать ваш код, как этот, поэтому, если вы вместо этого сможете вставить нам результат сборки SQL STRING, мы сможем затем отформатировать его как можно больше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...