Где я должен разместить индексы в таблицах MySQL - PullRequest
0 голосов
/ 22 сентября 2011

У меня есть три следующих пункта WHERE:

WHERE primaryId = $imgId AND imgWidth = $maxImageWidth AND imgHeight = $maxImageHeight

WHERE primaryId = $imgId AND imgWidth = $maxImageWidth AND imgHeight != $maxImageHeight

WHERE primaryId = $imgId AND imgWidth != $maxImageWidth AND imgHeight = $maxImageHeight"

Они действуют на две таблицы MySQL InnoDB, соединенные в запросе с UNION ALL.

Я не уверен, как мне настроить индексы в этих двух таблицах; Должен ли я иметь многостолбцовый индекс с imgWidth и imgHeight, или он должен также включать primaryId?

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

Или в этом случае многостолбцовый индекс не будет работать?


Вот пример всего запроса для первого предложения WHERE. Остальные такие же, с соответствующими пунктами:

SELECT 'allEqual' AS COL1,COUNT(*) AS imgCount FROM (
    SELECT imgHeight, imgWidth, imgId AS primaryId FROM primary_images
    UNION ALL 
    SELECT imgHeight, imgWidth, primaryId FROM secondary_images
) AS union_table
WHERE primaryId = $imgId AND imgWidth = $maxImageWidth AND imgHeight = $maxImageHeight

Вот схема таблицы primary_images:

CREATE  TABLE IF NOT EXISTS `new_arrivals_images`.`primary_images` (
  `imgId` SMALLINT(6) UNSIGNED NOT NULL AUTO_INCREMENT ,
  `imgTitle` VARCHAR(255) NULL DEFAULT NULL ,
  `view` VARCHAR(45) NULL DEFAULT NULL ,
  `secondary` ENUM('true','false') NOT NULL DEFAULT false ,
  `imgURL` VARCHAR(255) NULL DEFAULT NULL ,
  `imgWidth` SMALLINT(6) UNSIGNED NULL DEFAULT NULL ,
  `imgHeight` SMALLINT(6) UNSIGNED NULL DEFAULT NULL ,
  `imgDate` DATETIME NULL DEFAULT NULL ,
  `imgClass` ENUM('Jeans','T-Shirts','Shoes','Dress Shirts','Trackwear & Sweatwear') NULL DEFAULT NULL ,
  `imgFamily` ENUM('Hugo Boss','Lacoste','True Religion','7 For All Mankind','Robin\'s Jeans','Robert Graham') NULL DEFAULT NULL ,
  `imgGender` ENUM('Men\'s','Women\'s') NOT NULL DEFAULT Mens ,
  PRIMARY KEY (`imgId`) ,
  UNIQUE INDEX `imgDate_UNIQUE` (`imgDate` DESC) )
ENGINE = InnoDB;

И схема для таблицы secondary_images:

CREATE  TABLE IF NOT EXISTS `new_arrivals_images`.`secondary_images` (
  `imgId` SMALLINT(6) UNSIGNED NOT NULL AUTO_INCREMENT ,
  `primaryId` SMALLINT(6) UNSIGNED NOT NULL ,
  `view` VARCHAR(45) NULL DEFAULT NULL ,
  `imgURL` VARCHAR(255) NULL DEFAULT NULL ,
  `imgWidth` SMALLINT(6) UNSIGNED NULL DEFAULT NULL ,
  `imgHeight` SMALLINT(6) UNSIGNED NULL DEFAULT NULL ,
  `imgDate` DATETIME NULL DEFAULT NULL ,
  PRIMARY KEY (`imgId`, `primaryId`) ,
  INDEX `fk_secondary_images_primary_images` (`primaryId` ASC) ,
  UNIQUE INDEX `imgDate_UNIQUE` (`imgDate` DESC) ,
  CONSTRAINT `fk_secondary_images_primary_images`
    FOREIGN KEY (`primaryId` )
    REFERENCES `new_arrivals_images`.`primary_images` (`imgId` )
    ON DELETE CASCADE
    ON UPDATE CASCADE)
ENGINE = InnoDB;

Ответы [ 2 ]

2 голосов
/ 22 сентября 2011

Правда ли, что запрос может использовать только один индекс?

Нет.Это было бы глупо.

Если нет, могу ли я настроить каждый столбец как индекс?

Да, это вариант, но только если вы используете столбец независимо друг от друга.
Если вы всегда комбинируете поля, как вы, кажется, делаете здесь, более эффективно использовать соединениеindex.

Я не уверен, как мне настроить индексы в этих двух таблицах;Должен ли я иметь многостолбцовый индекс с imgWidth и imgHeight или он должен также включать primaryId?

Если вы хотите использовать комбинированный индекс, объединяющий (imgWidth, imgHeight)
Вы должны помнить, что вы не можете получить доступ к индексу на imgHeight без использования imgWidth в whereпредложение.
Вы всегда должны использовать самую левую часть (или всю) составного индекса.

На InnoDB первичный ключ всегда включается в каждый вторичный индекс, поэтому включать это контрпродуктивно.

Добавлен бонус на InnoDB
Если вы выбираете толькоВ индексированных полях InnoDB никогда не будет читать данные таблицы, поскольку все необходимые данные находятся в индексе.Это значительно ускорит процесс.

У вас есть дыра для SQL-инъекций
Кажется, в вашем коде есть дыра для SQL-инъекций.Пожалуйста, заключите все свои $ vars в одинарные кавычки: where field1 = '$var' ... и не забудьте использовать $var = mysql_real_escape_string($var); перед тем, как вводить их в запрос.См .: Как работает SQL-инъекция из комикса XKCD «Таблицы Бобби»?

Для скорости и безопасности запрос должен выглядеть следующим образом:

SELECT 'allEqual' AS COL1, COUNT(*) AS imgCount FROM (
    SELECT imgId AS primaryId FROM primary_images pi
    WHERE pi.ImgId = '$imgId' 
      AND pi.imgWidth = '$maxImageWidth' 
      AND pi.imgHeight = '$maxImageHeight'
    UNION ALL 
    SELECT primaryId FROM secondary_images si
    WHERE si.primaryId = '$imgId' 
      AND si.imgWidth = '$maxImageWidth'    
      AND si.imgHeight = '$maxImageHeight'  
) AS union_table                      

Таким образом,будут использоваться правильные индексы, и не будут получены ненужные данные.
MySQL не может использовать индекс для объединенных данных, потому что это объединение двух разных таблиц.Вот почему вам нужно сделать where во внутренних выборках.

1 голос
/ 22 сентября 2011

Есть ли в вашем столбце primaryId дубликаты?Или это первичный ключ?Если это первичный ключ, то он также будет служить точным указателем.В InnoDB это, вероятно, уже индекс, если он является первичным ключом.

Другими словами, насколько различает ваше предложение WHERE primaryId = $imgId?Если он обычно не соответствует ни одному, или точно одной, или нескольким строкам, то другой индекс мало поможет.Если он соответствует сотням или тысячам строк, может помочь другой индекс.

Запросы могут определенно использовать несколько индексов.

Это один из тех случаев, когда большой вопрос "что вы пытаетесь сделать?"Кажется, вы пытаетесь выбрать изображение, в котором одно или оба измерения соответствуют вашему вводу.

Попробуйте сделать его более эффективным, изменив логику и избавившись от предложения UNION ALL (которое превращается в три запроса).

    WHERE primaryId = $imgId 
      AND (imgWidth = $maxImageWidth OR imgHeight = $maxImageHeight)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...