2015-03-27 2 views
1

Есть ли способ оптимизировать следующий MySql-запрос?Slow MySQL Query/Large DB/JOIN

SELECT article.* 
FROM article 
WHERE channelid = 1 
AND ((SELECT count(*) FROM article_cCountry WHERE ID1 = article.id AND ID2 = 1) = 1) 
AND date < now() 
AND released = "TRUE" 
AND ((uId = 0) OR ((SELECT count(*) FROM user WHERE ID = article.uId and released = true) = 1)) 
ORDER BY cDate DESC 
LIMIT 20 

Я уже пытался использовать INNER JOIN для проверки article_cCountry, но выступление было еще хуже.

EDIT

Структура для article_cCountry

| ID | ID1 | ID2 | (ID1 => article.id, ID2 => country) 

Структура для пользователя пользователя

Около 20 столбцов с пользовательскими данными

+0

косяка у помочь нам помочь U, обеспечивая структуру таблицы для связанных таблиц ? – rezashamdani

+0

- это запрос для «выбора всей статьи с помощью channelid = 1 и даты до этого и выпущен и только из страны-производителя, которая имеет только 1 статью и показана только для пользователя, который ее написал, выпущена, которая только пишет 1, или иначе ни один пользователь не написал ее , '? попытайтесь использовать онлайн-тестирование для запроса, поэтому вы можете разместить свои таблицы там, не можете видеть только эту информацию – rezashamdani

+0

да, но: с помощью «SELECT count (*) ... = 1», я имел в виду «Статьи из этого страна ", так как счетчик (*) вернет 0, если статья не из страны« 1 ». То же самое относится к пользовательскому запросу – grundig

ответ

0

Попробуйте объяснить запрос с:

EXPLAIN SELECT ... 

Если вы не используете какой-либо индекс пытаются поставить индекс на полях, используемых в где:

article.date 
article.channelid 
article.released 
user.released 
article_cCountry.id1 
article_cCountry.id2 
0

попробовать это:.

ВЫБРАТЬ статью * ОТ статья ВХОДНАЯ СТРАНИЦА article_cCountry ON article.id = article_cCountry.ID1 INNER JOIN USER ПО article.uId = USER .id ГДЕ channelid = 1 И article_cCountry.ID2 = 1 И USER .released = TRUE И ДАТА < СООБЩЕНИЕ() и выпущен = TRUE ORDER BY DESC CDate ПРЕДЕЛ 20;

1

Я не уверен, что вам нужно проверить

SELECT article.*, COUNT(ac.id) ac_count, COUNT(u.id) u_count 
FROM article 
    INNER JOIN article_cCountry ac ON ac.ID1 = article.id AND ac.ID2 = 1 
    INNER JOIN user u ON u.ID = article.uId and u.released 
WHERE 
    channelid = 1 
    AND date < now() 
    AND released = "TRUE" 
GROUP BY article.id 
HAVING ac_count = 1 AND (uId = 0 OR u_count = 1) 
ORDER BY cDate DESC 
LIMIT 20 
0

Попробуйте положить ваши подзапросов в временные таблицы

CREATE TEMPORARY TABLE COUNTRY 
(
    countryCount INT, 
    articleId INT 
) 
INSERT INTO 
    COUNTRY 
SELECT 
    COUNT(1), 
    ID1, 
FROM 
    article_cCountry 
WHERE 
    ID2 = 1 
GROUP BY 
    ID1 

CREATE TEMPORARY TABLE USERS 
(
    userCount INT, 
    articleId INT 
) 
INSERT INTO 
    USERS 
SELECT 
    COUNT(1), 
    ID 
FROM 
    [user] 
WHERE 
    released = true 
GROUP BY 
    ID 

SELECT 
    article.* 
FROM 
    article JOIN COUNTRY country ON country.articleId = article.id 
     JOIN USERS users ON users.articleId = article.uId 
WHERE 
    channelid = 1 
AND 
    --((SELECT count(*) FROM article_cCountry WHERE ID1 = article.id AND ID2 = 1) = 1) 
    country.countryCount = 1 
AND 
    date < now() 
AND 
    released = "TRUE" 
AND 
    ( 
     (uId = 0) 
    OR 
     --((SELECT count(*) FROM user WHERE ID = article.uId and released = true) = 1)) 
     (users.userCount = 1) 
    ) 
ORDER BY 
    cDate DESC 
LIMIT 20 

DROP TABLE COUNTRY; 
DROP TABLE USERS;