[英]MySQL LEFT JOIN or WHERE IN SUBQUERY
我需要一條建議,現在構建一個應用程序,我需要在相當大的表上運行一些查詢,可能是非常頻繁的,所以我試圖獲得最佳的方法性能明智。
我有以下2個表格:
專輯:
+---------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| eventid | int(11) | NO | MUL | NULL | |
| album | varchar(200) | NO | | NULL | |
| filename | varchar(200) | NO | | NULL | |
| obstacle_time | time | NO | | NULL | |
+---------------+--------------+------+-----+---------+----------------+
和關鍵字:
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| eventid | int(11) | NO | MUL | NULL | |
| filename | varchar(200) | NO | | NULL | |
| bibnumbers | varchar(200) | NO | | NULL | |
| gender | varchar(20) | YES | | NULL | |
| top_style | varchar(20) | YES | | NULL | |
| pants_style | varchar(20) | YES | | NULL | |
| other | varchar(20) | YES | | NULL | |
| cap | varchar(200) | NO | | NULL | |
| tshirt | varchar(200) | NO | | NULL | |
| pants | varchar(200) | NO | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
兩個表都聲明了unique_index,它是eventid+filename
列的約束。
兩個表都包含有關某些圖像的信息,但是相冊表立即可用(只要我有圖像),而關鍵字表通常在手動標記圖像完成幾天后可用
現在,一旦啟用標記,我會讓人們搜索所有類型的東西,但由於結果可能很大(高達10.000或更多)我只是以小塊顯示它們所以瀏覽器不會因嘗試而被殺死加載大量圖像,因此我的服務器將被大量的查詢請求命中(每次訪問者滾動到頁面底部時,ajax查詢將返回下一個圖像塊)。
現在我的問題是,以下哪個查詢性能更好:
SELECT `albums`.`filename`,`basket`.`id`,`albums`.`id`,`obstacle_time`
FROM `albums`
LEFT JOIN `basket`
ON `basket`.`eventid` = `albums`.`eventid`
AND `basket`.`fileid` = `albums`.`id`
AND `basket`.`visitor_id` = 1
LEFT JOIN `keywords`
ON `keywords`.`eventid` = `albums`.`eventid`
AND `albums`.`filename` = `keywords`.`filename`
WHERE
`albums_2015`.`eventid` = 1
AND `album` LIKE '%string%'
AND `obstacle_time` >= '08:00:00'
AND `obstacle_time` <= '14:11:10'
AND `gender` = 1
AND `top_style` REGEXP '[[:<:]]0[[:>:]]|[[:<:]]1[[:>:]]'
AND `cap` = '2'
AND `tshirt` = '1'
AND `pants` = '3'
ORDER BY `obstacle_time`
LIMIT X, 10
或者在WHERE
使用IN
CLAUSE:
SELECT `albums`.`filename`,`basket`.`id`,`albums`.`id`,`obstacle_time`
FROM `albums`
LEFT JOIN `basket`
ON `basket`.`eventid` = `albums`.`eventid`
AND `basket`.`fileid` = `albums`.`id`
AND `basket`.`visitor_id` = 1
WHERE
`albums_2015`.`eventid` = 1
AND `album` LIKE '%string%'
AND `obstacle_time` >= '08:00:00'
AND `obstacle_time` <= '14:11:10'
AND `filename` IN (
SELECT `filename`
FROM `keywrods`
WHERE
`eventid` = 1
AND `gender` = 1
AND `top_style` REGEXP '[[:<:]]0[[:>:]]|[[:<:]]1[[:>:]]'
AND `cap` = '2'
AND `tshirt` = '1'
AND `pants` = '3'
)
ORDER BY `obstacle_time`
LIMIT X, 10
我曾經看過類似的問題,但無法弄清楚哪個是最好的行動方案。
到目前為止,我的理解是:
使用LEFT JOIN
可以利用INDEXING,但是!!! 如果我使用它,即使我只需要一個非常小的結果集,我也會獲得表的完全連接,因此加入數千行只是為了過濾掉大部分行,這幾乎是一個浪費。
使用IN和子查詢沒有索引??? 我不是百分之百地確定這一點,我使用的是MySQL 5.6並且我的理解最好,因為5.6甚至子查詢都會自動索引我的MySQL。 我認為當結果被顯着過濾時,此方法會有好處,如果子查詢將返回所有可能的文件名,則不確定是否會有任何好處。
作為腳注問題:
我是否應該考慮在第一個查詢時將整個結果返回給客戶端,並使用客戶端(HTML)技術逐步加載圖像而不是每次都重新查詢服務器?
我是否應該考慮將2個表合並為1,這將產生多大的性能影響? (由於種種原因可能很棘手,問題中沒有任何地方)
謝謝。
編輯1
解釋JOIN查詢:
+----+-------------+---------------+--------+---------------+--------------+---------+----------------------------------------+------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------------+--------+---------------+--------------+---------+----------------------------------------+------+----------------------------------------------------+
| 1 | SIMPLE | albums_2015 | ref | unique_index | unique_index | 4 | const | 6475 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | basket | ALL | NULL | NULL | NULL | NULL | 2 | Using where; Using join buffer (Block Nested Loop) |
| 1 | SIMPLE | keywords_2015 | eq_ref | unique_index | unique_index | 206 | const,mybibnumber.albums_2015.filename | 1 | Using index |
+----+-------------+---------------+--------+---------------+--------------+---------+----------------------------------------+------+----------------------------------------------------+
使用WHERE IN:
+----+-------------+---------------+--------+---------------+--------------+---------+----------------------------------------+------+----------------------------------------------------+--+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | |
+----+-------------+---------------+--------+---------------+--------------+---------+----------------------------------------+------+----------------------------------------------------+--+
| 1 | SIMPLE | albums_2015 | ref | unique_index | unique_index | 4 | const | 6475 | Using where; Using temporary; Using filesort | |
| 1 | SIMPLE | keywords_2015 | eq_ref | unique_index | unique_index | 206 | const,mybibnumber.albums_2015.filename | 1 | Using where | |
| 1 | SIMPLE | basket | ALL | NULL | NULL | NULL | NULL | 2 | Using where; Using join buffer (Block Nested Loop) | |
+----+-------------+---------------+--------+---------------+--------------+---------+----------------------------------------+------+----------------------------------------------------+--+
編輯2
我無法設置SQL Fiddler(不斷出錯的錯誤),所以我在我的一台服務器上創建了一個測試數據庫。
地址: http : //188.165.217.185/phpmyadmin/,user : temp_test ,pass: test_temp
我還在構建整個東西,但我還沒有填寫所有值,比如top_style,pants_style等,所以測試場景的更合適的查詢將是:
在哪里:
SELECT `albums_2015`.`filename`,
`albums_2015`.`id`,
`obstacle_time`
FROM `albums_2015`
WHERE `albums_2015`.`eventid` = 1
AND `album` LIKE '%'
AND `obstacle_time` >= '08:00:00'
AND `obstacle_time` <= '14:11:10'
AND `filename` IN (SELECT `filename`
FROM `keywords_2015`
WHERE eventid = 1
AND
`bibnumbers` REGEXP '[[:<:]]113[[:>:]]|[[:<:]]106[[:>:]]')
ORDER BY `obstacle_time`
LIMIT 0, 10
LEFT JOIN
SELECT `albums_2015`.`filename`,`albums_2015`.`id`,`obstacle_time`
FROM `albums_2015`
LEFT JOIN `keywords_2015`
ON `keywords_2015`.`eventid` = `albums_2015`.`eventid`
AND `albums_2015`.`filename` = `keywords_2015`.`filename`
WHERE
`albums_2015`.`eventid` = 1
AND `album` LIKE '%'
AND `obstacle_time` >= '08:00:00'
AND `obstacle_time` <= '14:11:10'
AND `bibnumbers` REGEXP '[[:<:]]113[[:>:]]|[[:<:]]106[[:>:]]'
ORDER BY `obstacle_time`
LIMIT 0, 10
更多一些提示:
不要介意添加一些索引來加速你的查詢(索引占用空間,但在INT
字段上它沒什么,你獲得的收益遠遠超過你的損失)。
TAG_table
上的插入觸發器用於緩存遠程表格中顯示的部分(如專輯概述的標記名稱),可幫助您將連接查詢保持在下降頻率。
REGEX
,它會嚴重傷害穿孔 。 添加新表以分割數據是一個更好的主意(並使用索引,這是本機優化) WHERE
子句中的每個字段,您應該有一個索引。 如果你不能放一個,那么你的數據庫模型就可以了,需要更改。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.