MySQL Join Optimization - PullRequest
       10

MySQL Join Optimization

0 голосов
/ 12 ноября 2009

Можете ли вы помочь мне оптимизировать этот запрос. Я использую этот запрос, чтобы получить список друзей вместе с их данными и их статусом. Обработка этого на Athlon X2 6000

занимает около 0,08 сек.

Я также не могу использовать materizlized view, потому что он часто меняется.

SELECT p.userid, p.firstname, p.lastname, p.gender, p.dob, x.relationship,
 IF(p.picture !=1, 
   IF(p.gender != 'm','/sc/f-t.jpg','/sc/m-t.jpg'),
   concat('/sc/pthumb/', p.userid, '.jpg' )) AS picture
  FROM `social` AS p
  LEFT JOIN `friendlist` AS f1 ON (f1.`userid` = p.`userid` AND f1.`friendid` = 1 AND `f1`.`status` = 1)
  LEFT JOIN `friendlist` AS f2 ON (f2.`friendid` = p.`userid` AND f2.`userid` = 1 AND `f2`.`status` = 1)
  LEFT JOIN `x_relationship` AS x ON (x.`id` = p.`relationship`)
  LEFT JOIN `auth` as a ON (a.`userid` = p.`userid`) 
  WHERE 1 AND (f1.`userid` IS NOT NULL OR f2.`userid` IS NOT NULL AND ((a.`banned` != 1 AND a.`deleted` != 1)))
  ORDER BY RAND() LIMIT 0,10

1 Ответ

5 голосов
/ 12 ноября 2009

Это ваш оригинальный запрос, отформатированный. Ниже несколько мыслей.

SELECT 
  p.userid, 
  p.firstname, 
  p.lastname, 
  p.gender, 
  p.dob, 
  x.relationship,
  IF(p.picture !=1, IF(p.gender != 'm', '/sc/f-t.jpg', '/sc/m-t.jpg'), concat('/sc/pthumb/', p.userid, '.jpg' )) AS picture
FROM 
  `social` AS p
  LEFT JOIN `friendlist`     AS f1 ON (f1.`friendid` = 1          AND f1.`userid` = p.`userid` AND `f1`.`status` = 1)
  LEFT JOIN `friendlist`     AS f2 ON (f2.`friendid` = p.`userid` AND f2.`userid` = 1          AND `f2`.`status` = 1)
  LEFT JOIN `x_relationship` AS  x ON (x.`id` = p.`relationship`)
  LEFT JOIN `auth`           AS  a ON (a.`userid` = p.`userid`) 
WHERE 
  1 
  AND (
    f1.`userid` IS NOT NULL 
    OR f2.`userid` IS NOT NULL 
    AND (a.`banned` != 1 AND a.`deleted` != 1)
  )
ORDER BY 
  RAND() 
LIMIT 
  0,10

Подумайте, могут ли некоторые из ваших левых соединений быть внутренними. Если это так, измените их.

Ваше предложение WHERE испорчено. Вы смешиваете И и ИЛИ без правильной расстановки приоритетов в скобках. Попробуйте:

WHERE 
  a.`banned` != 1 
  AND a.`deleted` != 1
  AND (
    f1.`userid` IS NOT NULL 
    OR f2.`userid` IS NOT NULL
  )

Вы также можете попробовать:

  INNER JOIN `auth` AS  a ON (
    a.`userid` = p.`userid` 
    AND a.`banned` != 1 
    AND a.`deleted` != 1
  ) 
WHERE 
  f1.`userid` IS NOT NULL 
  OR f2.`userid` IS NOT NULL

Вы, кажется, присоединяетесь к friendlist исключительно для проверки существования записи. Вы также можете попробовать это:

FROM 
  `social` AS p
  INNER JOIN `auth`           AS  a ON (
    a.`userid` = p.`userid`
    AND a.`banned` != 1 
    AND a.`deleted` != 1
  ) 
  LEFT  JOIN `x_relationship` AS  x ON (
    x.`id` = p.`relationship`
  )
WHERE 
  EXISTS (
    SELECT 1 FROM `friendlist` WHERE `friendid` = 1 AND `userid` = p.`userid` AND `status` = 1
  ) 
  OR EXISTS (
    SELECT 1 FROM `friendlist` WHERE `friendid` = p.`userid` AND `userid` = 1 AND `status` = 1
  )

ORDER BY RAND() может быть не самая быстрая вещь на земле, но если это то, что вам нужно ... Попробуйте упорядочить по проиндексированному столбцу, чтобы увидеть, какое влияние оказывает ORDER BY RAND().

Индексация:

  • Вы должны создать составной индекс для friendlist(friendid, userid, status).
  • Убедитесь, что есть индекс relationship(id)
  • Убедитесь, что на auth(userid)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...