我应该在哪里放置索引在MySQL表中

时间:2011-09-21 21:12:15

标签: mysql database database-design indexing

我有以下三个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"

他们正在使用UNION ALL在查询中加入两个MySQL InnoDB表。

我不确定如何在这两个表中设置索引;我是否应该拥有包含imgWidthimgHeight的多列索引,或者是否应包含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 个答案:

答案 0 :(得分:2)

  

查询只能使用一个索引吗?

没有。那太傻了。

  

如果没有,我可以将每列设置为索引吗?

是的,这是一个选项,但仅限于您彼此独立使用列 如果你总是把字段组合在一起,就好像你在这里做的那样,使用复合索引会更有效。

  

我不确定如何在这两个表中设置索引;我是否应该有一个多列索引,imgWidth和imgHeight,或者它是否应该包含primaryId?

如果您想使用组合(imgWidth, imgHeight)的复合索引 您必须记住,如果imgHeight没有在imgWidth子句中使用where,则无法访问where field1 = '$var' ...上的索引。 您必须始终使用复合索引的最左侧部分(或全部)。

在InnoDB上,主键始终包含在每个二级索引中,因此包含它会适得其反。

在InnoDB上添加了奖励
如果您只选择索引字段,InnoDB将永远不会实际读取tabledata,因为所需的所有数据都在索引中。这将加速很多事情。

你有一个SQL注入孔
您的代码似乎有一个SQL注入漏洞。请用单引号括起所有$ vars:$var = mysql_real_escape_string($var);并且在将它们注入查询之前不要忘记使用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 。请参阅:How does the SQL injection from the "Bobby Tables" XKCD comic work?

为了提高速度和安全性,查询应为:

where

这样就可以使用正确的索引,也不会检索到不需要的数据 MySQL不能在联合数据上使用索引,因为它是两个不同表的合并。这就是你需要在内部选择中进行{{1}}的原因。

答案 1 :(得分:1)

您的primaryId列是否有任何重复项?或者它是主键?如果它是主键,那么它也将作为一个精细的索引。在InnoDB中,如果它是主键,它可能已经是一个索引。

换句话说,您的WHERE子句primaryId = $imgId有多么区别?如果它通常匹配none,或者只匹配一行,或者只是几行,那么另一个索引将无济于事。如果它匹配数百或数千行,则另一个索引可能会有所帮助。

查询肯定可以使用多个索引。

这是其中一个重大问题是“你想做什么?”的案例之一。您似乎正在尝试选择其中一个或两个尺寸与您的输入相匹配的图像。

考虑通过重做逻辑并删除你的UNION ALL子句(变成三个查询)来提高效率。

    WHERE primaryId = $imgId 
      AND (imgWidth = $maxImageWidth OR imgHeight = $maxImageHeight)