2011-09-21 21 views
0

我有以下三個WHERE條款:我應該在哪裏放置指標的MySQL表

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

我不知道我應該如何設置這兩個表中的索引;我是否應該有多列索引,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; 
+1

你的代碼是一個SQL注入漏洞。請將所有'$ vars'用單引號括起來:'where field1 ='$ var'...'並且在將它們注入查詢之前不要忘記使用'$ var = mysql_real_escape_string($ var)'。請參閱:http://stackoverflow.com/questions/332365/xkcd-sql-injection-please-explain – Johan

回答

2

這是真的,一個查詢只能使用一個索引?

不,那會很愚蠢。

如果不是,我可以設置每列作爲索引?

是的,這是一個選項,但只有當你使用彼此獨立的列。
如果您總是將這些字段組合在一起,就好像您在這裏所做的那樣,使用複合索引效率更高。

我不知道我應該如何設置這兩個表中的索引;我是否應該有多列索引,使用imgWidth和imgHeight,還是應該包含primaryId?

如果你想可以使用複合索引結合(imgWidth, imgHeight)
你必須記住,雖然你不能沒有where子句中也在使用imgWidthimgHeight訪問索引。
您必須始終使用複合索引的最左側部分(或全部)。

在InnoDB上,主鍵總是包含在每個二級索引中,所以包含這一點會適得其反。在InnoDB上

額外的獎勵如果僅選擇索引字段時,InnoDB將永遠不會實際讀取的資料表,因爲所有需要的數據是在索引中。這會加速很多事情。

您有一個SQL注入孔
您的代碼似乎有一個SQL注入漏洞。請將所有$變量用單引號括起來:where field1 = '$var' ...並且在將它們注入查詢之前不要忘記使用$var = mysql_real_escape_string($var);。請參閱:How does the SQL injection from the "Bobby Tables" XKCD comic work?

對於速度和安全性的查詢應爲:

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

+0

這是一個熱辣的回答約翰。你更清楚地解釋了我幾天來一直在閱讀的內容。謝謝一堆。我很好奇,我有另外一個查詢,其中WHERE子句是可變的,也就是說內容根據情況而變化。如果我在另一個問題中發佈它,你會介意看看嗎? – stefmikhail

+0

是的,但不是今天,我現在要去睡覺了。如果你在下面提出一個評論,並附上一個問題的鏈接,我會看看它2morrow。 – Johan

+0

好吧,所以荷蘭......我認爲這比我早8小時;)所以我會在*我*睡覺之前張貼它,然後你應該在那時起牀!再次感謝。 – stefmikhail

1

您的primaryId列是否有任何重複S'或者它是主鍵?如果它是主鍵,那麼它也將成爲一個很好的索引。在InnoDB中,如果它是主鍵,它可能已經是一個索引。

換言之,您的WHERE子句primaryId = $imgId有多歧視?如果它通常不匹配,或者恰好匹配一個,或者只匹配幾行,那麼另一個索引不會有太大的幫助。如果它匹配數百或數千行,另一個索引可能會有所幫助。

查詢絕對可以使用多個索引。

這是一個大問題是「你想要做什麼?」的情況之一。看起來你正在嘗試選擇一個圖片,其中一個或兩個尺寸都與您的輸入相符。

考慮通過重做邏輯並擺脫UNION ALL子句(將其轉換爲三個查詢)來提高效率。

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

我添加了其餘查詢的示例,以及兩個表的組成。我正在出發,但我會盡力回答任何問題,並儘快對您的答案發表評論。非常感謝你的迴應。 :) – stefmikhail