Я пытаюсь оптимизировать базу данных MySQL для запроса, который в настоящее время очень медленно:
SELECT Listing.*, PrimaryPhoto.*
FROM listings AS Listing
LEFT JOIN file_storage AS PrimaryPhoto
ON (PrimaryPhoto.foreign_key = Listing.ID
AND PrimaryPhoto.model = 'PrimaryListingPhoto')
WHERE Listing.rent >= 0
AND Listing.rent <= 5000
AND Listing.beds >= 1
AND Listing.is_active = '1'
ORDER BY Listing.modified DESC
Я добавил несколько индексов к listings
Таблица…
…и вот индексы для file_storage
Таблица…
…но это все еще очень медленно! Как 20 + секунд, чтобы бежать.
EXPLAIN
показывает мне, что filesort
используется:
Я думал, что смогу предотвратить filesort
добавив индекс для всех 4 столбцов, упомянутых в WHERE
а также ORDER BY
пункт. Но это не сработало.
Я сделал что-то неправильно? Или, возможно, я не в том месте, чтобы ускорить этот запрос.
Обновить
Вот схема для двух таблиц:
CREATE TABLE IF NOT EXISTS `listings` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL COMMENT 'ID of user who owns this listing',
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`address` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT 'Street address (w/o postal code)',
`lat` decimal(10,8) DEFAULT NULL,
`lng` decimal(11,8) DEFAULT NULL,
`postal_code` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
`description` text COLLATE utf8_unicode_ci NOT NULL,
`rent` int(11) NOT NULL COMMENT 'Monthly rental price in CAD',
`lease_length` int(11) DEFAULT NULL COMMENT '# of months of lease',
`date_available` date DEFAULT NULL COMMENT 'Day the listing is available',
`neighborhood_id` int(11) NOT NULL,
`beds` int(11) NOT NULL COMMENT '# of bedrooms',
`baths` int(11) NOT NULL COMMENT '# of bathrooms',
`sq_ft` int(11) DEFAULT NULL COMMENT '# of square footage',
`fridge` tinyint(1) NOT NULL,
`stove` tinyint(1) NOT NULL,
`dishwasher` tinyint(1) NOT NULL,
`ac` tinyint(1) NOT NULL,
`furnished` tinyint(1) NOT NULL,
`laundry` tinyint(1) NOT NULL,
`balcony` tinyint(1) NOT NULL,
`patio` tinyint(1) NOT NULL,
`yard` tinyint(1) NOT NULL,
`pool` tinyint(1) NOT NULL,
`doorman` tinyint(1) NOT NULL,
`security` tinyint(1) NOT NULL,
`gym` tinyint(1) NOT NULL,
`parking` tinyint(1) NOT NULL,
`wheelchair` tinyint(1) NOT NULL,
`inc_heat` tinyint(1) NOT NULL COMMENT 'does the rent include heat?',
`inc_water` tinyint(1) NOT NULL COMMENT 'doest the rent include water?',
`inc_internet` tinyint(1) NOT NULL COMMENT 'does the rent include internet?',
`inc_cable` tinyint(1) NOT NULL COMMENT 'does the rent include cable?',
`cats` tinyint(1) NOT NULL COMMENT 'are cats allowed?',
`small_dogs` tinyint(1) NOT NULL COMMENT 'are small dogs allowed?',
`big_dogs` tinyint(1) NOT NULL COMMENT 'are big dogs allowed?',
`is_active` tinyint(1) NOT NULL COMMENT 'is the listing active?',
`is_hot` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'hot list',
`source_url` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`source_email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
PRIMARY KEY (`ID`),
KEY `user_id` (`user_id`),
KEY `is_active` (`is_active`),
KEY `rent` (`rent`),
KEY `rent_beds_is_active` (`rent`,`beds`,`is_active`),
KEY `modified` (`modified`),
KEY `rent_beds_active_modified` (`rent`,`beds`,`is_active`,`modified`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=3012 ;
CREATE TABLE IF NOT EXISTS `file_storage` (
`id` varchar(36) COLLATE utf8_unicode_ci NOT NULL,
`user_id` varchar(36) COLLATE utf8_unicode_ci DEFAULT NULL,
`foreign_key` varchar(36) COLLATE utf8_unicode_ci DEFAULT NULL,
`model` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`filename` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`filesize` int(16) DEFAULT NULL,
`mime_type` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL,
`extension` varchar(5) COLLATE utf8_unicode_ci DEFAULT NULL,
`hash` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`path` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`adapter` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'Gaufrette Storage Adapter Class',
`created` datetime DEFAULT NULL,
`modified` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `foreign_key` (`foreign_key`),
KEY `model_foreign_key` (`model`,`foreign_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Это ваш запрос:
SELECT Listing.*, PrimaryPhoto.*
FROM listings AS Listing LEFT JOIN
file_storage AS PrimaryPhoto
ON PrimaryPhoto.foreign_key = Listing.ID AND
PrimaryPhoto.model = 'PrimaryListingPhoto'
WHERE Listing.rent >= 0 AND Listing.rent <= 5000 AND
Listing.beds >= 1 AND
Listing.is_active = '1'
ORDER BY Listing.modified DESC
Попробуйте этот составной индекс (порядок ключей важен): Listing(beds, is_active, modified, rent)
, Полный индекс на where
(то есть, beds, is_active, rent)
не поможет с order by
, Этот может. Кроме того, вы хотите индекс на file_storage(foreign_key, model)
,
Удалите индексы в PrimaryPhoto.model и удалите объединение, добавьте его в предложение where. Ваш запрос должен выглядеть так:
SELECT Listing.*, PrimaryPhoto.*
FROM listings AS Listing
LEFT JOIN file_storage AS PrimaryPhoto
ON PrimaryPhoto.foreign_key = Listing.ID
WHERE Listing.rent >= 0
AND Listing.rent <= 5000
AND Listing.beds >= 1
AND Listing.is_active = '1'
AND PrimaryPhoto.model = 'PrimaryListingPhoto'
ORDER BY Listing.modified DESC
Также постарайтесь не делать выбор с *
выберите только необходимые столбцы.