Mysql - Оптимизация запросов - PullRequest
       7

Mysql - Оптимизация запросов

0 голосов
/ 26 октября 2019

У меня есть схема БД как таковая,

SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';

-- -----------------------------------------------------
-- Schema stack_vista
-- -----------------------------------------------------

-- -----------------------------------------------------
-- Schema stack_vista
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `stack_vista` DEFAULT CHARACTER SET utf8 ;
USE `stack_vista` ;

-- -----------------------------------------------------
-- Table `stack_vista`.`csv`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `stack_vista`.`csv` (
  `idcsv` INT NOT NULL AUTO_INCREMENT,
  `serviceCode` VARCHAR(45) NULL,
  `offerDate` DATETIME NULL,
  `price` VARCHAR(45) NULL,
  `offerDuration` INT NULL,
  `occupancy` INT NULL,
  `extra_cols` VARCHAR(45) NULL,
  PRIMARY KEY (`idcsv`),
  INDEX `index_service_code` (`serviceCode` ASC))
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `stack_vista`.`offers`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `stack_vista`.`offers` (
  `idoffers` INT NOT NULL AUTO_INCREMENT,
  `shipSlug` VARCHAR(45) NULL,
  `offerLink` VARCHAR(45) NULL,
  `name` VARCHAR(45) NULL,
  `serviceCode` VARCHAR(45) NULL,
  `extra_cols` VARCHAR(45) NULL,
  PRIMARY KEY (`idoffers`),
  INDEX `index_offer_code` (`serviceCode` ASC),
  FULLTEXT INDEX `index_ship_slug` (`shipSlug` ASC))
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `stack_vista`.`ships`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `stack_vista`.`ships` (
  `idships` INT NOT NULL AUTO_INCREMENT,
  `slug` VARCHAR(45) NULL,
  `name` VARCHAR(45) NULL,
  PRIMARY KEY (`idships`),
  FULLTEXT INDEX `index_slug` (`slug` ASC))
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `stack_vista`.`props`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `stack_vista`.`props` (
  `idprops` INT NOT NULL AUTO_INCREMENT,
  `idoffers` INT NOT NULL,
  `propName` VARCHAR(45) NULL,
  `propCode` VARCHAR(45) NULL,
  `type` VARCHAR(45) NULL,
  PRIMARY KEY (`idprops`),
  INDEX `fk_props_offers_idx` (`idoffers` ASC),
  INDEX `index_type` (`type` ASC),
  CONSTRAINT `fk_props_offers`
    FOREIGN KEY (`idoffers`)
    REFERENCES `stack_vista`.`offers` (`idoffers`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `stack_vista`.`location`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `stack_vista`.`location` (
  `idlocation` INT NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(45) NULL,
  `code` VARCHAR(45) NULL,
  `type` VARCHAR(45) NULL,
  PRIMARY KEY (`idlocation`),
  INDEX `index_type` (`type` ASC),
  INDEX `index_name` (`name` ASC))
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `stack_vista`.`offers_has_location`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `stack_vista`.`offers_has_location` (
  `offers_idoffers` INT NOT NULL,
  `location_idlocation` INT NOT NULL,
  PRIMARY KEY (`offers_idoffers`, `location_idlocation`),
  INDEX `fk_offers_has_location_location1_idx` (`location_idlocation` ASC),
  INDEX `fk_offers_has_location_offers1_idx` (`offers_idoffers` ASC),
  CONSTRAINT `fk_offers_has_location_offers1`
    FOREIGN KEY (`offers_idoffers`)
    REFERENCES `stack_vista`.`offers` (`idoffers`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT `fk_offers_has_location_location1`
    FOREIGN KEY (`location_idlocation`)
    REFERENCES `stack_vista`.`location` (`idlocation`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;


SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

Моя таблица csv - это таблица, в которую я добавляю данные, импортированные из csv, и предлагает предложения для разных услуг / поездок, для разных дат, местоположенияи типы. Он может иметь 10000-100000 записей, около 900-1000 сервисов и их комбинацию, как видно из group by.

Различные сервисы отображаются в servicCode из таблицы offers, которая уникальна в offersтаблица.

Некоторые из offers имеют shipSlugs, что соответствует slugs в таблице ships.

Я пытаюсь перечислить все возможные serviceCodesofferDate, propTypeId и shipSlug. Так как существуют другие факторы, например, csv.extra_cols и csv.offerDuration, которые влияют на цену, я просто хотел получить MIN(Price) на основе столбцов, используемых в GROUP BY, следовательно, агрегации.

Iдобавили индекс в каждый столбец, который включается либо в условие where, либо в условия объединения.

Мой запрос, указанный ниже, в настоящее время занимает от 6 до 9 секунд. Что еще можно сделать для оптимизации этого запроса:

SELECT 
    i.serviceCode AS serviceCode,
    i.offerDate AS offerDate,
    MIN(i.price) AS price,
    i.offerDuration AS duration,
    i.occupancy AS occupancy,
    p.idprops AS propTypeId,
    p.propName AS propTypeName,
    p.propCode AS propTypeCode,
    p.type AS type,
    g.idlocation AS destinationId,
    g.name AS destinationName,
    g.code AS destinationCode,
    g.type AS destinationType,
    o.idoffers AS offerId,
    o.offerlink AS offerlink,
    o.name AS name,
    o.shipSlug AS shipSlug,
    s.name AS shipName,
    CONCAT_WS('-',
            YEAR(i.offerDate),
            MONTH(i.offerDate)) AS offer_year_month_date
FROM
    csv i
        JOIN
    offers o ON o.serviceCode = i.serviceCode
        LEFT JOIN
    ships s ON o.shipSlug = s.slug
        JOIN
    props p ON o.idoffers = p.idoffers
        JOIN
    offers_has_location og ON o.idoffers = og.offers_idoffers
        JOIN
    location g ON g.idlocation = og.location_idlocation
WHERE
    p.type = 'travelType'
        AND g.code IN ('Earth' , 'River', 'HighLands')
GROUP BY serviceCode, offer_year_month_date, propTypeId, shipSlug;

1 Ответ

0 голосов
/ 27 октября 2019

Одно простое замечание: если имя столбца совпадает с результатом AS, вам не нужна AS. Только если вы изменяете результат имени столбца или результат какой-либо функции, такой как min / max, concat_ws и т. Д.

Что касается группировки по. Вы должны включить все неагрегированные столбцы как часть группы, чтобы он не выдавал ошибку. Итак, вещи ex: lookup description, которые никогда не изменятся в зависимости от их идентификатора, вы можете использовать min () или max (). Другой подход заключается в том, чтобы предварительно агрегировать все, кроме описаний кода поиска, сохраняя идентификаторы, ТО затем объединяться для получения описаний поиска.

Вы ищете определенный тип и код, я бы попытался оптимизировать, начиная с этого. Я также реструктурировал запрос и с помощью MySQL использую предложение «STRAIGHT_JOIN», которое сообщает движку, чтобы он выполнял запрос в указанном мной порядке.

Теперь я сделал все группы не по столбцам с MIN() поэтому запрос будет правильно получать минимальную цену за тип проп, код обслуживания, корабль, год / месяц. Но это больше похоже на деятельность туристических агентств с разными направлениями / направлениями. Не имея более реалистичных образцов данных, я думаю, что эти приложения MIN () для других элементов не будут иметь смысла. Вам может понадобиться больше, чем это. Пример: круиз, основанный на одноместном размещении, очевидно, будет менее двухместного размещения. Таким образом, наличие места в составе группы имело бы смысл. Поездка из порта A в B будет полностью отличаться от порта A до C, поэтому я ожидаю, что пункт назначения и пункты назначения также будут частью группы.

Я думаю, что вам действительно нужно утверждать свои данные о том, что вы просите, чтобы они действительно имели смысл в ваших результатах.

SELECT STRAIGHT_JOIN
      p.idprops AS propTypeId,
      o.serviceCode,
      o.shipSlug,
      CONCAT_WS('-',
         YEAR(i.offerDate),
         MONTH(i.offerDate)) AS offer_year_month_date,
      min(i.offerDate ) FirstOfferDate,
      min(i.price) AS price,
      min(i.offerDuration ) AS MinDuration,
      min( i.occupancy ) MinOccupancy,
      min( p.propName ) AS propTypeName,
      min( p.propCode ) AS propTypeCode,
      min( p.type ) as type,
      min( g.idlocation ) AS destinationId,
      min( g.name ) AS destinationName,
      min( g.code ) AS destinationCode,
      min( g.type ) AS destinationType,
      min( o.idoffers ) AS offerId,
      min( o.offerlink ) AS offerlink,
      min( o.name ),
      min( s.name ) AS shipName
   FROM
      props p 
        JOIN offers o
           ON p.idoffers = o.idoffers 
           JOIN csv i
              ON o.serviceCode = i.serviceCode
           LEFT JOIN
              ships s ON o.shipSlug = s.slug
        JOIN offers_has_location og 
           ON p.idoffers = og.offers_idoffers
           JOIN location g 
              ON og.location_idlocation = g.idlocation
             AND g.code IN ('Earth' , 'River', 'HighLands')
   WHERE
      p.type = 'travelType'
   GROUP BY 
      serviceCode, offer_year_month_date, propTypeId, shipSlug;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...