Таблицы:
CREATE TABLE IF NOT EXISTS `posts` (
`post_n` int(10) NOT NULL auto_increment,
`id` int(10) default NULL,
`date` datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (`post_n`,`visibility`),
KEY `id` (`id`),
KEY `date` (`date`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE IF NOT EXISTS `subscriptions` (
`subscription_n` int(10) NOT NULL auto_increment,
`id` int(10) NOT NULL,
`subscribe_id` int(10) NOT NULL,
PRIMARY KEY (`subscription_n`),
KEY `id` (`id`),
KEY `subscribe_id` (`subscribe_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
Query:
SELECT posts.* FROM posts, subscriptions
WHERE posts.id=subscriptions.subscribe_id AND subscriptions.id=1
ORDER BY date DESC LIMIT 0, 15
Это так медленно, потому что используемые индексы "id", "subscribe_id", но не индекс "дата", поэтому упорядочение происходит очень медленно.
Есть ли какие-либо опции для изменения запроса, индексов, архитектуры?
Возможные улучшения:
Во-первых, вы получите пару микросекунд за запрос, если вы назовете свои поля вместо использования сообщений SELECT. *, который вызывает поиск схемы. Измените свой запрос на:
SELECT posts.post_n, posts.id, posts.date
FROM posts, subscriptions
WHERE posts.id=subscriptions.subscribe_id
AND subscriptions.id=1
ORDER BY date DESC
LIMIT 0, 15
Далее, для этого требуется MySQL 5.1 или новее, но вам может потребоваться разделить ваши таблицы. Вы можете рассмотреть раздел KEY для обеих таблиц.
Это должно помочь вам начать. http://dev.mysql.com/doc/refman/5.1/en/partitioning-types.html
например.
SET SQL_MODE = 'ANSI';
-- to allow default date
CREATE TABLE IF NOT EXISTS `posts` (
`post_n` int(10) NOT NULL auto_increment,
`id` int(10) default NULL,
`date` datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (`post_n`,`id`),
KEY `id` (`id`),
KEY `date` (`date`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin
PARTITION BY KEY(id) PARTITIONS 32;
--
CREATE TABLE IF NOT EXISTS `subscriptions` (
`subscription_n` int(10) NOT NULL auto_increment,
`id` int(10) NOT NULL,
`subscribe_id` int(10) NOT NULL,
PRIMARY KEY (`subscription_n`,`subscribe_id`),
KEY `id` (`id`),
KEY `subscribe_id` (`subscribe_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin
PARTITION BY KEY(subscribe_id) PARTITIONS 32;
Мне пришлось немного изменить свой первичный ключ. Поэтому, будьте осторожны, это НЕ МОЖЕТ РАБОТАТЬ для вас. Пожалуйста, проверьте его и убедитесь. Надеюсь, это правда. Обязательно запустите sysbench против старых и новых структур/запросов, чтобы сравнить результаты перед тем, как перейти к производству. : -)
Если вы можете изменить таблицу, вы можете добавить индекс с несколькими полями, содержащий как идентификатор, так и дату. (или изменить один из существующих ключей, чтобы содержать их оба).
Если вы не можете внести изменения в базу данных, и если вы знаете, что ваш результирующий набор будет небольшим, вы можете заставить его использовать определенный именованный ключ с USE KEY(name)
. После этого заказ будет выполнен после факта, как раз на возвращенных reslts.
Надеюсь, что это поможет.