我应该在 MySQL 表中放置索引
我有以下三个 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 表。
我不确定应该如何在这两个表中设置索引;我是否应该有一个带有 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;
I have the following three WHERE
clauses:
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"
They are acting upon two MySQL InnoDB tables joined in the query with UNION ALL
.
I am not sure how I should set up the Indexes in these two tables; Whether I should have a Multi-Column Index, with imgWidth
and imgHeight
, or if it should include primaryId
as well?
Is it true that a query can only use one index? If not, could I set up each column as an index?
Or would a Multi-Column Index not work in this case?
Here is an example of the entire query for the first WHERE
clause. The others are the same, with the respective clauses:
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
Here is the schema of the primary_images
table:
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;
And the schema for the secondary_images
table:
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;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不,那太愚蠢了。
是的,这是一个选项,但前提是您彼此独立地使用该列。
如果您总是组合字段(就像您在这里所做的那样),那么使用复合索引会更有效。
如果您想可以使用组合索引
(imgWidth, imgHeight)
但您必须记住,如果不在
where
子句中使用imgWidth
,则无法访问imgHeight
上的索引。您必须始终使用复合索引的最左边部分(或全部)。
在 InnoDB 上,主键始终包含在每个二级索引中,因此包含它会适得其反。
增加了 InnoDB 的奖励
如果只选择索引字段,InnoDB将永远不会真正读取表数据,因为所需的所有数据都在索引中。这会大大加快速度。
您有一个 SQL 注入漏洞
你的代码似乎有一个 SQL 注入漏洞。请将所有 $var 用单引号引起来:
where field1 = '$var' ...
并且不要忘记使用$var = mysql_real_escape_string($var);
在将它们注入查询之前。 参阅:“Bobby Tables”XKCD 漫画中的 SQL 注入是如何工作的?请 查询应读取的速度和安全性:
这样将使用正确的索引并且不会检索不需要的数据。
MySQL 无法对联合数据使用索引,因为它是两个不同表的合并。这就是为什么您需要在内部选择中执行
where
的原因。No. That would be silly.
Yes that's an option, but only if you use the column independently of each other.
If you always combine the fields, like it seems you do here, it's more efficient to use a compound index.
If you want to can use a compound index combining
(imgWidth, imgHeight)
You must remember though that you cannot access the index on
imgHeight
without also usingimgWidth
in thewhere
clause.You must always use the left-most part (or all) of a compound index.
On InnoDB the primary key is always included in every secondary index, so it is counterproductive to include that.
Added bonus on InnoDB
If you only select indexed fields, InnoDB will never actually read the tabledata, because all the data needed is in the index. This will speed up things a lot.
You have an SQL-injection hole
Your code seems to have an SQL-injection hole. Please surround all your $vars in single quotes:
where field1 = '$var' ...
and don't forget to use$var = mysql_real_escape_string($var);
before injecting them into the query. See: How does the SQL injection from the "Bobby Tables" XKCD comic work?For speed and safety the query should read:
This way the proper indexes will be used and no unneeded data is retrieved.
MySQL cannot use an index on the unioned data because it's a merge of two different tables. That's why you need to do the
where
in the inner selects.您的 PrimaryId 列是否有重复项?或者它是主键吗?如果它是主键,那么它也将充当精细索引。在InnoDB中,如果它是主键,它可能已经是索引了。
换句话说,您的 WHERE 子句
primaryId = $imgId
的区分度如何?如果它通常不匹配任何行,或者恰好匹配一行,或者只匹配几行,那么另一个索引不会有太大帮助。如果它匹配数百或数千行,另一个索引可能会有所帮助。查询肯定可以使用多个索引。
在这种情况下,最大的问题是“你想做什么?”您似乎正在尝试选择其中一个或两个尺寸与您的输入相匹配的图像。
考虑通过重做逻辑并删除 UNION ALL 子句(变成三个查询)来提高效率。
Does your primaryId column have any duplicates? Or is it a primary key? If it's a primary key, then it will also serve as a fine index. In InnoDB, it probably already is an index if it's a primary key.
Put another way, how discriminating is your WHERE clause
primaryId = $imgId
? If it typically matches none, or exactly one, or just a few rows, then another index won't help much. If it matches hundreds or thousands of rows, another index may well help.Queries can definitely use multiple indexes.
This is one of those cases where the big question is "what are you trying to do?" It seems like you're trying to select an image where either or both dimensions match your input.
Consider making it more efficient by redoing the logic and getting rid of your UNION ALL clause (which turns into three queries).