2010-04-27 299 views
3
SELECT 
    items.item_id, items.category_id, items.title, items.description, items.quality, 
    items.type, items.status, items.price, items.posted, items.modified, 
    zip_code.state_prefix, zip_code.city, books.isbn13, books.isbn10, books.authors, 
    books.publisher 
FROM 
(
    (
    items 
    LEFT JOIN bookitems ON items.item_id = bookitems.item_id 
) 
    LEFT JOIN books ON books.isbn13 = bookitems.isbn13 
) 
LEFT JOIN zip_code ON zip_code.zip_code = items.item_zip 
WHERE items.rid = $rid` 

我正在運行此查詢以獲取用戶項目及其位置的列表。 zip_code表有超過40k條記錄,這可能是問題所在。目前需要15秒才能返回約20件物品的清單!我能做些什麼來使這個查詢更有效率?MySQL緩慢查詢

更新:以下是相關表的表創建代碼。對格式化抱歉!

CREATE TABLE `bookitems` ( 
    `bookitem_id` int(10) unsigned NOT NULL auto_increment COMMENT 'BookItem ID', 
    `item_id` int(10) unsigned NOT NULL default '0' COMMENT 'Item ID', 
    `isbn13` varchar(13) NOT NULL default '' COMMENT 'Book ISBN13', 
    `modified` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP COMMENT 'Date of Last Modification', 
    PRIMARY KEY (`bookitem_id`), 
    UNIQUE KEY `item_id` (`item_id`), 
    KEY `fk_bookitems_isbn13` (`isbn13`), 
    CONSTRAINT `fk_bookitems_isbn13` FOREIGN KEY (`isbn13`) REFERENCES `books` (`isbn13`), 
    CONSTRAINT `fk_bookitems_item_id` FOREIGN KEY (`item_id`) REFERENCES `items` (`item_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=82 DEFAULT CHARSET=latin1; 

CREATE TABLE `books` ( 
    `isbn13` varchar(13) NOT NULL default '' COMMENT 'Book ISBN13 (pk)', 
    `isbn10` varchar(10) NOT NULL default '' COMMENT 'Book ISBN10 (u)', 
    `title` text NOT NULL COMMENT 'Book Title', 
    `title_long` text NOT NULL, 
    `authors` text NOT NULL COMMENT 'Book Authors', 
    `publisher` text NOT NULL COMMENT 'ISBNdb publisher_text', 
    PRIMARY KEY (`isbn13`), 
    UNIQUE KEY `isbn10` (`isbn10`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

CREATE TABLE `items` ( 
    `item_id` int(10) unsigned NOT NULL auto_increment COMMENT 'Item ID', 
    `rid` int(10) unsigned NOT NULL default '0' COMMENT 'Item Owner User ID', 
    `category_id` int(10) unsigned NOT NULL default '0' COMMENT 'Item Category ID', 
    `title` tinytext NOT NULL COMMENT 'Item Title', 
    `description` text NOT NULL COMMENT 'Item Description', 
    `quality` enum('0','1','2','3','4','5') NOT NULL default '0' COMMENT 'Item Quality', 
    `type` enum('forsale','wanted','pending') NOT NULL default 'pending' COMMENT 'Item Status', 
    `price` int(6) unsigned NOT NULL default '0' COMMENT 'Price', 
    `posted` datetime NOT NULL default '0000-00-00 00:00:00' COMMENT 'Date of Listing', 
    `modified` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP COMMENT 'Date of Last Modification', 
    `status` enum('sold','found','flagged','removed','active','expired') NOT NULL default 'active', 
    `item_zip` int(5) unsigned zerofill NOT NULL default '00000', 
    PRIMARY KEY (`item_id`), 
    KEY `fk_items_rid` (`rid`), 
    KEY `fk_items_category_id` (`category_id`), 
    CONSTRAINT `fk_items_category_id` FOREIGN KEY (`category_id`) REFERENCES `categories` (`category_id`), 
    CONSTRAINT `fk_items_rid` FOREIGN KEY (`rid`) REFERENCES `users` (`rid`) 
) ENGINE=InnoDB AUTO_INCREMENT=123 DEFAULT CHARSET=latin1; 

CREATE TABLE `users` ( 
    `rid` int(10) unsigned NOT NULL auto_increment COMMENT 'User ID', 
    `fid` int(10) unsigned NOT NULL default '0' COMMENT 'Facebook User ID', 
    `role_id` int(10) unsigned NOT NULL default '4', 
    `zip` int(5) unsigned zerofill NOT NULL default '00000' COMMENT 'Zip Code', 
    `joined` timestamp NOT NULL default CURRENT_TIMESTAMP COMMENT 'INSERT Timestamp', 
    `email` varchar(255) NOT NULL default '', 
    `notes` varchar(255) NOT NULL default '', 
    PRIMARY KEY (`rid`), 
    UNIQUE KEY `fid` (`fid`), 
    KEY `fk_users_role` (`role_id`), 
    CONSTRAINT `fk_users_role` FOREIGN KEY (`role_id`) REFERENCES `roles` (`role_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=1013 DEFAULT CHARSET=latin1; 

CREATE TABLE `zip_code` ( 
    `id` int(11) unsigned NOT NULL auto_increment, 
    `zip_code` varchar(5) character set utf8 collate utf8_bin NOT NULL, 
    `city` varchar(50) character set utf8 collate utf8_bin default NULL, 
    `county` varchar(50) character set utf8 collate utf8_bin default NULL, 
    `state_name` varchar(50) character set utf8 collate utf8_bin default NULL, 
    `state_prefix` varchar(2) character set utf8 collate utf8_bin default NULL, 
    `area_code` varchar(3) character set utf8 collate utf8_bin default NULL, 
    `time_zone` varchar(50) character set utf8 collate utf8_bin default NULL, 
    `lat` float NOT NULL, 
    `lon` float NOT NULL, 
    `search_string` varchar(52) NOT NULL default '', 
    PRIMARY KEY (`id`), 
    KEY `zip_code` (`zip_code`) 
) ENGINE=MyISAM AUTO_INCREMENT=42625 DEFAULT CHARSET=utf8; 
+0

您是否使用'EXPLAIN'查看了查詢計劃?你能發佈每個表的'SHOW CREATE TABLE'的輸出,加上'EXPLAIN SELECT ...'的輸出嗎? – 2010-04-27 16:47:49

+0

您在JOIN列索引上使用的所有列? – bobince 2010-04-27 16:48:48

+0

如果你正在使用phpmyadmin,你也可以點擊'建議表結構'鏈接獲取一些提示。 – SeanJA 2010-04-27 16:56:05

回答

5
SELECT items.item_id, 
     items.category_id, 
     items.title, 
     items.description, 
     items.quality, 
     items.TYPE, 
     items.status, 
     items.price, 
     items.posted, 
     items.modified, 
     zip_code.state_prefix, 
     zip_code.city, 
     books.isbn13, 
     books.isbn10, 
     books.authors, 
     books.publisher 
FROM items 
LEFT JOIN 
     bookitems 
ON  bookitems.item_id = items.item_id 
LEFT JOIN 
     books 
ON  books.isbn13 = bookitems.isbn13 
LEFT JOIN 
     zip_code 
ON  zip_code.zip_code = items.item_zip 
WHERE items.rid = $rid 

創建以下指標:

items (rid) 
bookitems (item_id) 
books (isbn13) 
zip_code (zip_code) 
+0

+1發現的舊記錄多出10k條記錄,我剛纔輸入的內容是 – 2010-04-27 16:49:59

+0

+1,我也是:)。 – 2010-04-27 16:51:13

+0

我在想,'WHERE'需要首先過濾'items',而不是在所有的塊(')都被檢索出來之後。 – 2010-04-27 16:53:25

0

您的第一個選擇應該是優化您的數據庫。 所有這些40k行有用的數據?或者您可以將一些舊數據移動到包含存檔數據的表格中嗎?你使用適當的索引?這樣的例子不勝枚舉..

+0

zip_code表中的每條40k記錄代表一個郵政編碼,城市名稱,州,州縮寫,縣和經緯度座標。無法真正擺脫任何數據。實際上,最新數據庫包含的記錄數比我多年前通過http://www.micahcarrick.com – andrhamm 2010-04-27 18:24:50

0

第一個問題是你有什麼指標。你有zip_code(zip_code)索引嗎?你的其他桌子有多大?正如我所說,顯然幫助的索引是zip_code(zip_code),然後是項目(rid),bookitems(item_id)和books(isbn13)。

我想你幾乎可以肯定想要在zip_code上的索引,這幾乎可以用在任何針對該表的查詢中。您可能還需要在isbn13和bookitems(item_id)上使用索引。我不知道什麼項目(擺脫)應該是。一個索引將有助於這個查詢,但可能會或可能不會有用。

除此之外,查詢中沒有明顯的缺陷。

順便說一句,「左項加入書目......」的括號是多餘的。表格默認從左到右連接。

0

我不知道這只是通過查看查詢,但

看來你與字符串數據類型加入您行,就是有點慢於使用整數,如標識進行比較,特別是如果沒有索引。