Вход на хостинг
IT-новости
20.04.2016 iPhone 2017 года поместят в водонепроницаемый корпус из стекла
Линейка iPhone в новом году серьезно поменяется. В этом уверен аналитический исследователь Мин Чи Ку......
30.07.2015 Ищем уникальный контент для сайта
Ищем уникальный контент для сайта Без уникального контента Ваш сайт обречен на то, что его страницы......
SELECT user_id, MAX(posts_id)
FROM posts
WHERE user_id
IN (SELECT friend_id
FROM friends
WHERE user_id = UserId)
GROUP BY user_id;
Для максимально оптимальной выборки необходимо на внутренний запрос подключить индекс по первичному ключу таблицы friends, а для внешнего запроса – первичный ключ по таблице posts.
Однако, поскольку MySQL всех версий не умеет адекватно оптимизировать внешний запрос вне зависимости от созданных индексов и их явного указния через FORCE(key list), разбиваем сложный запрос на два простых: в первом запросе получаем список пользователей, а во втором – выбираем посты.
UsersSet = SELECT friend_id FROM friends WHERE user_id = UserId
и
SELECT user_id, MAX(post_id) FROM posts WHERE user_id in (UsersSet) GROUP BY user_id
Я не утверждаю, что MySQL 5 не умеет делать подзапросы. Утверждается, что скорость работы двух простых запросов выше скорости работы одного сложного ввиду специфических особенностей работы оптимизатора запросов.
Чтение постов и комментариев:
SELECT *
FROM posts
WHERE (posts_id = PostId);
SELECT *
FROM comments
WHERE ((user_id = UserId) AND (posts_id = PostId))
ORDER BY comment_date;
Запись поста:
PostID = SELECT MAX(post_id) FROM posts;
INSERT IGNORE INTO posts (user_id, post_id, post_date, post_title, post_body) VALUES (UserID, PostID, Date, Title, Body);
Запись комментария:
SELECT COUNT(*) FROM users WHERE (user_id = iUserId);
SELECT COUNT(*) FROM users WHERE (user_id = iPosterId);
SELECT COUNT(*) FROM posts WHERE (post_id = iPostId);
CommentId = SELECT MAX(comment_id) FROM commnets; INSERT IGNORE INTO
comments (user_id, posts_id, comment_id, from_user_id, comment_date, comment_title, comment_body)
VALUES (UserId, PostId, CommentId, PosterId, Date, Title, Body);</pre>
Создание пользователя:
SELECT COUNT(1) FROM users WHERE user_name = UserName;
INSERT INTO users(user_name) VALUES (UserName);
GET_LAST_INSERT_ID
Редактирование свойств пользователя:
SELECT COUNT(1) FROM users WHERE user_id = UserId;
UPDATE users SET user_name = UserName WHERE user_id = UserId;
Как мы можем видеть, алгоритмы работы с БД оптимизированны как под MySQL, так и под PostgreSQL.
Важно отметить, что не существует одинаковых архитектурных решений для этих двух СУБД. В каждом случае требуется индивидуальный подход как в проектировании структуры базы данных, так и в реализации механизма вставок и выборок данных.
Именно поэтому в высоконагруженных проектах недопустимо использование «универсальных» фреймворков для БД, поскольку ни один из них не учитывает архитектуру проекта, в котором используется, а большинство их них не учитывает даже порядка использования индексов в СУБД.
Поговорим про оптимизацию кода. Разумеется, количество «служебных» запросов (проверок наличия или отсутствия пользователя, комментариев и т. п.) можно сократить, введя, например, users_id как хэшированное имя пользователя или разместив в памяти хэштаблицу ID и имен пользователей. Однако здесь мы тестируем производительность именно СУБД, а не всего программного комплекса в целом.
Результаты
Я сознательно не измерял время подключения к БД, а использовал пул заранее созданных подключений. На наш взгляд, отсутствие пула и постоянные переподключения к базе у высоконагруженного проекта – уже показатель его неправильной архитектуры.
Результаты тестирования СУБД MySQL и PostgreSQL в зависимости от количества подключений
Количество коннектов в пуле |
MySQL InnoDB (read/write per sec) |
MySQL MyISAM (read/write per sec) |
PostgreSQL (read/write per sec) |
1 |
600/60 |
500/20 |
4000/1500 |
5 |
1100/110 |
600/50 |
12000/3000 |
10 |
1100/110 |
600/50 |
14000/4000 |
11-17 |
800/70 |
400/30 |
14000/4000 |
20 и более |
Отказ от обслуживания |
Отказ от обслуживания |
14000/4000 |