MySQL левого соединения занимает слишком много времени - PullRequest
3 голосов
/ 28 февраля 2012

У меня есть следующий SQL-запрос:

SELECT 
    upd.*,
    usr.username AS `username`,
    usr.profile_picture AS `profile_picture`
FROM 
    updates AS upd
LEFT JOIN 
    subscribers AS sub ON upd.uid=sub.suid
LEFT JOIN 
    users AS usr ON upd.uid=usr.uid
WHERE 
    upd.deleted='0' && (upd.uid='118697835834' || sub.uid='118697835834')
GROUP BY upd.id
ORDER BY upd.date DESC
LIMIT 0, 15

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

Однако, поскольку обновления становятся все больше и больше, поэтому запросу требуется больше времени для загрузки ... прямо сейчас, используя Codeigniter Profiler, я могу видеть, что запрос занимает 1.3793 ...

Сейчас я создал около 18 тыс. Фиктивных учетных записей и подписался на меня и наоборот, чтобы я мог проверить время выполнения ... времена, которые я получаю, трагичны, учитывая, что я нахожусь в localhost ...

У меня также есть некоторые индексы, в которых, я полагаю, нужно больше в таблице пользователей (имя пользователя и uid как уникальные), таблица обновлений (update_id как уникальный и uid как индекс)

Я полагаю, что я делаючто-то не так, чтобы получить такие плохие результаты ...

РЕДАКТИРОВАТЬ : Запуск EXPLAIN EXTENDED результат:

Array
(
    [0] => stdClass Object
        (
            [id] => 1
            [select_type] => SIMPLE
            [table] => upd
            [type] => ALL
            [possible_keys] => i2
            [key] => 
            [key_len] => 
            [ref] => 
            [rows] => 22
            [filtered] => 100.00
            [Extra] => Using where; Using temporary; Using filesort
        )

    [1] => stdClass Object
        (
            [id] => 1
            [select_type] => SIMPLE
            [table] => sub
            [type] => ALL
            [possible_keys] => 
            [key] => 
            [key_len] => 
            [ref] => 
            [rows] => 18244
            [filtered] => 100.00
            [Extra] => Using where
        )

    [2] => stdClass Object
        (
            [id] => 1
            [select_type] => SIMPLE
            [table] => usr
            [type] => eq_ref
            [possible_keys] => uid
            [key] => uid
            [key_len] => 8
            [ref] => site.upd.uid
            [rows] => 1
            [filtered] => 100.00
            [Extra] => 
        )

)

EDIT2: ПОКАЗАТЬ СОЗДАНИЕ таблиц Вкладка "Пользователи"le:

CREATE TABLE `users` (
 `id` bigint(20) NOT NULL AUTO_INCREMENT,
 `uid` bigint(20) NOT NULL,
 `username` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
 `email` text CHARACTER SET latin1 NOT NULL,
 `password` text CHARACTER SET latin1 NOT NULL,
 `profile_picture_full` text COLLATE utf8_unicode_ci NOT NULL,
 `profile_picture` text COLLATE utf8_unicode_ci NOT NULL,
 `date_registered` datetime NOT NULL,
 `activated` tinyint(1) NOT NULL,
 `closed` tinyint(1) NOT NULL,
 PRIMARY KEY (`id`),
 UNIQUE KEY `uid` (`uid`),
 UNIQUE KEY `username` (`username`)
) ENGINE=MyISAM AUTO_INCREMENT=23521 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

Таблица подписчиков:

CREATE TABLE `subscribers` (
 `id` bigint(20) NOT NULL AUTO_INCREMENT,
 `sid` bigint(20) NOT NULL,
 `uid` bigint(20) NOT NULL,
 `suid` bigint(20) NOT NULL,
 `date` datetime NOT NULL,
 PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=18255 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

Таблица обновлений:

CREATE TABLE `updates` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `update_id` bigint(19) NOT NULL,
 `uid` bigint(20) NOT NULL,
 `type` text COLLATE utf8_unicode_ci NOT NULL,
 `update` text COLLATE utf8_unicode_ci NOT NULL,
 `date` datetime NOT NULL,
 `total_likes` int(11) NOT NULL,
 `total_comments` int(11) NOT NULL,
 `total_favorites` int(11) NOT NULL,
 `category` bigint(20) NOT NULL,
 `deleted` tinyint(1) NOT NULL,
 `deleted_date` datetime NOT NULL,
 PRIMARY KEY (`id`),
 UNIQUE KEY `i1` (`update_id`),
 KEY `i2` (`uid`),
 KEY `deleted_index` (`deleted`)
) ENGINE=MyISAM AUTO_INCREMENT=23 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

Ответы [ 5 ]

2 голосов
/ 28 февраля 2012

Попробуйте это (без GROUP BY):

SELECT 
    upd.*,
    usr.username AS `username`,
    usr.profile_picture AS `profile_picture`
FROM 
        updates AS upd
    LEFT JOIN 
        users AS usr 
            ON  upd.uid = usr.uid
WHERE 
    upd.deleted='0' 
  AND 
    ( upd.uid='118697835834'
   OR EXISTS
      ( SELECT *
        FROM   subscribers AS sub 
        WHERE  upd.uid = sub.suid
          AND  sub.uid = '118697835834'
      )
    )
ORDER BY upd.date DESC
LIMIT 0, 15

По крайней мере, столбцы, используемые в объединениях, должны быть проиндексированы: updates.uid, users.uid и subscribers.suid.

Я бы также добавил индекс на subscribers.uid.

1 голос
/ 28 февраля 2012

не используйте объединения, попробуйте следующее:

select  *, 
        (select username from users where uid = upd.uid) as username,
        (select profile_picture from users where uid = upd.uid) as profile_picture,
from    updates as upd
WHERE 
    upd.deleted='0' && upd.uid='118697835834'

(не проверено!)

возможно, вам нужно проверить, существует ли подписчик в предложении where с другимsub-select.

Другим способом было бы объединение для вложенных элементов, а не для всей таблицы.Это также может повысить вашу производительность.

1 голос
/ 28 февраля 2012

Попробуйте:

SELECT 
    upd.*,
    usr.username AS `username`,
    usr.profile_picture AS `profile_picture`
FROM 
    updates AS upd
LEFT JOIN 
    subscribers AS sub ON upd.uid=sub.suid
LEFT JOIN 
    users AS usr ON upd.uid=usr.uid
WHERE 
    upd.deleted=0 and upd.uid in (118697835834,118697835834)
GROUP BY upd.id
ORDER BY upd.date DESC
LIMIT 0, 15

Обратите внимание, что ' был удален из числовых значений, а побитовые операторы заменены на обычные операторы.

0 голосов
/ 28 февраля 2012

Я думаю, вам лучше всего разделить этот запрос на выборку в пользовательской таблице, а затем объединить эти результаты с выборкой в ​​таблице подписчиков.

0 голосов
/ 28 февраля 2012

не должно занять слишком много времени, чтобы бежать; у вас есть индекс на «удален»? Что делает «GROUP BY id»? Это должен быть UID? Может ли получиться, если идентификатор на самом деле является просто инкрементом, уникальным идентификатором? (что было бы дорого и бессмысленно)

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