Ускорить запрос (~1 млн строк) в сложной таблице

прежде всего спасибо за ваше время, читая это.

Я работаю над веб-приложением PHP, которое имеет дело со следующими данными, на данный момент есть заметное время при попытке получить данные, особенно при детализации параметров. В настоящее время основными параметрами являются VehicleType, Make, Model, Year, InternetPrice и Mileage. Со временем будет использоваться еще больше столбцов. Другие столбцы из этого списка используются для отображения данных по всей странице, так как в одном экземпляре отображаются 10 записей.

Структура таблицы:

CREATE TABLE `vehicles` (
  `id` int(12) NOT NULL AUTO_INCREMENT,
  `DealerID` int(6) DEFAULT NULL,
  `VIN` varchar(17) DEFAULT NULL,
  `StockNumber` varchar(10) DEFAULT NULL,
  `Status` varchar(1) DEFAULT NULL,
  `VehicleType` int(1) DEFAULT NULL,
  `Year` int(4) DEFAULT NULL,
  `Make` varchar(13) DEFAULT NULL,
  `Model` varchar(24) DEFAULT NULL,
  `Trim` varchar(35) DEFAULT NULL,
  `Body` varchar(25) DEFAULT NULL,
  `VehicleClass` varchar(50) DEFAULT NULL,
  `VehicleCategory` varchar(6) DEFAULT NULL,
  `Mileage` int(6) DEFAULT NULL,
  `Transmission` varchar(24) DEFAULT NULL,
  `EngineDisplacement` varchar(7) DEFAULT NULL,
  `EngineSize` varchar(15) DEFAULT NULL,
  `Induction` varchar(25) DEFAULT NULL,
  `DriveTrain` varchar(3) DEFAULT NULL,
  `FuelType` varchar(9) DEFAULT NULL,
  `FuelEconomyCity` int(2) DEFAULT NULL,
  `FuelEconomyHighway` int(2) DEFAULT NULL,
  `FuelEconomyCombined` int(1) DEFAULT NULL,
  `Doors` int(1) DEFAULT NULL,
  `OEMColorCodeExterior` varchar(10) DEFAULT NULL,
  `OEMColorCodeInterior` varchar(10) DEFAULT NULL,
  `OEMColorNameExterior` varchar(49) DEFAULT NULL,
  `OEMColorNameInterior` varchar(10) DEFAULT NULL,
  `GenericColorExterior` varchar(35) DEFAULT NULL,
  `GenericColorInterior` varchar(38) DEFAULT NULL,
  `InternetPrice` int(6) DEFAULT NULL,
  `ComparisonPrice` int(6) DEFAULT NULL,
  `WholeSalePrice` varchar(10) DEFAULT NULL,
  `MSRP` varchar(10) DEFAULT NULL,
  `InternetSpecial` varchar(1) DEFAULT NULL,
  `OemModelCode` varchar(12) DEFAULT NULL,
  `HasWarranty` varchar(1) DEFAULT NULL,
  `CertificationWarranty` int(3) DEFAULT NULL,
  `WarrantyMonth` int(1) DEFAULT NULL,
  `WarrantyMiles` int(1) DEFAULT NULL,
  `CertificationNumber` varchar(7) DEFAULT NULL,
  `ServiceContract` varchar(1) DEFAULT NULL,
  `InServiceDate` varchar(19) DEFAULT NULL,
  `CertificationDate` varchar(19) DEFAULT NULL,
  `DateManufactured` varchar(19) DEFAULT NULL,
  `DateCreated` varchar(19) DEFAULT NULL,
  `DateUpdated` varchar(19) DEFAULT NULL,
  `DateRemoved` varchar(19) DEFAULT NULL,
  `DatePhotosUpdated` varchar(19) DEFAULT NULL,
  `Photos` int(2) DEFAULT NULL,
  `SuperSizePhotos` int(2) DEFAULT NULL,
  `AddendumDetails` varchar(10) DEFAULT NULL,
  `DepartmentComments` varchar(239) DEFAULT NULL,
  `VehicleComments` varchar(1987) DEFAULT NULL,
  `Options` varchar(2264) DEFAULT NULL,
  `PurchasePayment` decimal(5,2) DEFAULT NULL,
  `PurchaseDownPayment` decimal(6,2) DEFAULT NULL,
  `PurchaseTerm` int(2) DEFAULT NULL,
  `PurchaseDisclosure` varchar(10) DEFAULT NULL,
  `PurchaseRate` decimal(3,2) DEFAULT NULL,
  `LeasePayment` decimal(2,2) DEFAULT NULL,
  `LeaseDownPayment` decimal(2,2) DEFAULT NULL,
  `LeaseTerm` int(1) DEFAULT NULL,
  `LeaseDisclosure` varchar(10) DEFAULT NULL,
  `LeaseRate` decimal(2,2) DEFAULT NULL,
  `LeaseResidual` decimal(2,2) DEFAULT NULL,
  `Reserved1` varchar(10) DEFAULT NULL,
  `Reserved2` varchar(10) DEFAULT NULL,
  `Reserved3` varchar(10) DEFAULT NULL,
  `Reserved4` varchar(10) DEFAULT NULL,
  `Reserved5` varchar(10) DEFAULT NULL,
  `Reserved6` varchar(10) DEFAULT NULL,
  `sitecert` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `VIN` (`VIN`),
  KEY `Make` (`Make`),
  KEY `StockNumber` (`StockNumber`),
  KEY `Model` (`Model`),
  KEY `Trim` (`Trim`),
  KEY `Body` (`Body`),
  KEY `VehicleClass` (`VehicleClass`),
  KEY `Transmission` (`Transmission`),
  KEY `DealerID` (`DealerID`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=46527428 ;

И пример запроса:

SELECT *
FROM vehicles
WHERE Make = 'Audi'
    AND VehicleType = '0'
    AND Model = 'A4'
    AND InternetPrice BETWEEN 0 AND 999999
    AND Year BETWEEN 1983 AND 2015
    AND Mileage > 0
    AND DealerID IN ('AA'
        ,'156553'
        ,'229602'
        ,'160483'
        ,'2953'
        ,'161712'
        ,'228576'
        ,'228921'
        ,'7590'
        ,'20813'
        ,'158105'
        ,'160286'
        ,'164479'
        ,'164487'
        ,'182543'
        ,'158860'
        ,'186479'
        ,'227170'
        ,'226327'
        )
ORDER BY sitecert DESC
    ,InternetPrice DESC 
LIMIT 0, 10

Кто-нибудь может дать совет по оптимизации этого запроса или таблицы? Конечно, на странице есть другой код, но я приурочил его к этому запросу, который вызывает задержку.

Спасибо за вашу помощь!

ОБНОВИТЬ:

Объяснение MySQL:

id select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  vehicles    ref Make,Model,DealerID Model   75  const   1675    Using where; Using filesort

Год был обновлен до INT


person ITAdminNC    schedule 10.03.2014    source источник
comment
Вы смотрели на нормализацию?   -  person Achrome    schedule 10.03.2014
comment
Вы пытались использовать EXPLAIN, чтобы увидеть, как обрабатывается запрос? В частности, проверьте, выполняет ли он полное сканирование таблицы.   -  person Powerlord    schedule 10.03.2014
comment
Что показывает EXPLAIN в запросе?   -  person Mark Baker    schedule 10.03.2014
comment
@AshwinMukhija - я посмотрю на это. Эта таблица усекается и обновляется каждую ночь с помощью CSV-файла. Как вы думаете, это вызовет проблемы при разделении данных через cron?   -  person ITAdminNC    schedule 10.03.2014
comment
Насколько большой стол? ряды!   -  person Up_One    schedule 10.03.2014
comment
@justacodeguy Необходимо будет соответствующим образом обновить cron. Нормализация — это одна из первых вещей, на которую следует обратить внимание при оптимизации базы данных. Затем идет основное использование EXPLAIN для выявления узких мест.   -  person Achrome    schedule 10.03.2014
comment
Я обновил вопрос текущими данными explain. Я посмотрю на нормализацию. В настоящее время в таблице 1 004 040 строк.   -  person ITAdminNC    schedule 10.03.2014
comment
Нормализация не имеет ничего общего с этим вопросом.   -  person Your Common Sense    schedule 10.03.2014
comment
сколько времени это занимает? 1600 строк мне кажется изрядной суммой.   -  person Your Common Sense    schedule 10.03.2014
comment
Как насчет индексации таблицы? Это не потребует обновления индекса при каждой записи.   -  person SaschaM78    schedule 10.03.2014
comment
1600 строк — это просто пример с выбранными мной критериями. По сути, пользователь сможет сузить данные так же, как вы ожидаете, что расширенный поиск будет работать на любом классифицированном веб-сайте. Проблема, с которой я сталкиваюсь, заключается в том, что эти результаты возвращаются, когда поиск становится более сложным, когда у пользователя есть более строгие критерии... из которых может быть найдено 6-12 разных столбцов. Запрос корректируется в зависимости от того, какие данные выбрал пользователь. Если пользователь не выбрал определенное поле (например, пробег), то оно не добавляется в окончательный запрос.   -  person ITAdminNC    schedule 10.03.2014
comment
Все корректировки не должны усложнять запрос выше этих 1600. Просто будет отфильтровано больше записей - не имеет большого значения. Это реальная проблема, с которой вы столкнулись на самом деле, или вы просто заранее ее предвидите и опасаетесь?   -  person Your Common Sense    schedule 11.03.2014


Ответы (3)


В зависимости от вашей базы данных вы должны добавить индексы для следующих полей:

Make
VehicleType
Model
InternetPrice
Year
Mileage
DealerId

Год должен быть типом DATE, а не текстом (INT также имеет смысл).

Это должно решить вашу проблему.

person Balazs Gunics    schedule 10.03.2014
comment
У вас был тот же вопрос, который нужно было решить, и помог ли этот подход? - person Your Common Sense; 10.03.2014
comment
Вот как бы я поступил. Поиск в текстовых полях всегда сложнее, чем поиск в числах. - person Balazs Gunics; 10.03.2014
comment
Плохая идея ! Загрузка стола будет длиться вечно! после создания этих индексов - person Up_One; 10.03.2014
comment
Спасибо, что указали на это, это должно было быть INT, но я ускользнул от меня. Я играл с индексами в прошлом и не нашел улучшения удовлетворительным, что заставило меня поверить, что я могу сделать что-то еще, чтобы улучшить его. - person ITAdminNC; 10.03.2014
comment
Индексы ЯВЛЯЮТСЯ правильным выбором. И поскольку вы заявляете, что данные перезагружаются каждую ночь, просто сначала удалите индексы, усеките таблицу, загрузите новые данные и перестройте индексы. Это не займет много времени, и результатом наличия (правильных, составных) индексов для данных будет то, что у вас будут гораздо более быстрые запросы в течение дня. PS: я бы также предложил перейти на InnoDb; MyIsam предназначен только для игрушек (ИМХО). - person deroby; 10.03.2014

Мои советы:

  • использовать группу по марке
  • разделите вашу таблицу, столбцы могут быть полезны (сделать, год)
  • сохраните свою таблицу в движке inndb вместо myisam и создайте несколько кластерных индексов для обслуживания ваших предикатов!
person Up_One    schedule 10.03.2014
comment
Как эти вещи могут помочь? Группировка практически - person Your Common Sense; 10.03.2014
comment
запусти профиль по этому запросу и узнаешь! меньше ввода/вывода - person Up_One; 10.03.2014

В таком случае вы должны прочитать результаты EXPLAIN и соответствующим образом настроить индексы.

Однако для сортировки всего 1600 строк я бы вообще не стал беспокоиться. Если вы все еще хотите сделать это быстрее, кажется, вам нужен комбинированный ключ, который будет включать модель и сертификат сайта, за которым следует цена, оба в обратном порядке.

Это означает, что у вас должно быть два дополнительных столбца, в которых хранятся отрицательные значения sitecert и price. затем создайте индекс (Model, nsitecert, nInternetPrice) и закажите без DESC, чтобы исключить файловую сортировку.

Если у вас есть поисковые запросы, в которых используется не Модель, а любая комбинация параметров, то пришло время подумать о внешней поисковой системе, такой как Sphinx Search.

person Your Common Sense    schedule 10.03.2014
comment
? Я так смущен вашим ответом! Вы можете выразить это в терминах базы данных? например, что он может сделать mysql engine + улучшенная структура DML + порядок + группировка + меньше ввода-вывода - person Up_One; 10.03.2014
comment
Все, что я сделал, это предложил указатель структуры, которую я описал. - person Your Common Sense; 10.03.2014
comment
Вы сказали использовать группу из ниоткуда. - person Your Common Sense; 10.03.2014
comment
Я не думаю, что здесь виноват ORDER BY, а скорее WHERE. Все это добавление нового поля, чтобы избежать сортировки файлов, звучит как техно-выдумка ИМХО. Зачем вам пытаться сканировать 1 млн строк (чтобы сохранить только менее 2 тыс.) В правильном порядке, когда гораздо быстрее иметь правильный индекс, чтобы быстро найти эти 2 тыс. строк, а затем отсортировать их по мере необходимости. - person deroby; 10.03.2014
comment
@deroby Вот что я сказал. - person Your Common Sense; 10.03.2014