使用關鍵字搜索謂詞LIKE '%pattern%'
是sure way to cause poor performance,因爲它強制執行表掃描。
執行relational division查詢(即僅匹配所有三個條件匹配的影片)的最佳方法是爲每個條件查找單獨的行,然後將它們聯接在一起。
SELECT f.*, CONCAT_WS(' ', a1.ambienceName, a2.ambienceName, a3.ambienceName) AS ambiences
FROM Films AS f
INNER JOIN Films_Ambiences as fa1 ON f.id = fa1.film_id
INNER JOIN Ambiences AS a1 ON a1.id = fa1.ambience_id
INNER JOIN Films_Ambiences as fa2 ON f.id = fa2.film_id
INNER JOIN Ambiences AS a2 ON a2.id = fa2.ambience_id
INNER JOIN Films_Ambiences as fa3 ON f.id = fa3.film_id
INNER JOIN Ambiences AS a3 ON a3.id = fa3.ambience_id
WHERE (a1.ambienceName, a2.ambienceName, a3.ambienceName) = (?, ?, ?);
你需要一個額外的JOIN
到Films_Ambiences
和Ambiences
每個搜索詞。
您應該有一個ambienceName
索引,然後所有三個查找將更有效率。
ALTER TABLE Ambiences ADD KEY (ambienceName);
我相比,在最近的一次演講的關係劃分不同的解決方案:
回覆您的評論:
有沒有辦法改變這個查詢,以便在找到標準後顯示其餘的氛圍?
是的,但你必須加入一個更多的時間來爲電影全套的氛圍中:
SELECT f.*, GROUP_CONCAT(a_all.ambienceName) AS ambiences
FROM Films AS f
INNER JOIN Films_Ambiences as fa1 ON f.id = fa1.film_id
INNER JOIN Ambiences AS a1 ON a1.id = fa1.ambience_id
INNER JOIN Films_Ambiences as fa2 ON f.id = fa2.film_id
INNER JOIN Ambiences AS a2 ON a2.id = fa2.ambience_id
INNER JOIN Films_Ambiences as fa3 ON f.id = fa3.film_id
INNER JOIN Ambiences AS a3 ON a3.id = fa3.ambience_id
INNER JOIN Films_Ambiences AS fa_all ON f.id = fa_all.film_id
INNER JOIN Ambiences AS a_all ON a_all.id = fa_all.ambience_id
WHERE (a1.ambienceName, a2.ambienceName, a3.ambienceName) = (?, ?, ?)
GROUP BY f.id;
有沒有辦法改變這個查詢,從而使結果只有沒有更多的氛圍需要的電影?
上面的查詢應該這樣做。
查詢做什麼,我想,是尋找影片,其中包括給定的氛圍(所以它也發現,有更多的氛圍電影)。
對,查詢與電影不匹配,除非它匹配搜索條件中的所有三種氣氛。但是這部電影可能有其他的環境,除了搜索標準之外,所有電影的氛圍(搜索標準加上其他環境)收集爲GROUP_CONCAT(a_all.ambienceName)
。
我測試了這個例子:
mysql> INSERT INTO Ambiences (ambienceName)
VALUES ('funny'), ('scary'), ('1950s'), ('London'), ('bank'), ('crime'), ('stupid');
mysql> INSERT INTO Films (title)
VALUES ('Mary Poppins'), ('Heist'), ('Scary Movie'), ('Godzilla'), ('Signs');
mysql> INSERT INTO Films_Ambiences
VALUES (1,1),(1,2),(1,4),(1,5), (2,1),(2,2),(2,5),(2,6), (3,1),(3,2),(3,7), (4,2),(4,3), (5,2),(5,7);
mysql> SELECT f.*, GROUP_CONCAT(a_all.ambienceName) AS ambiences
FROM Films AS f
INNER JOIN Films_Ambiences as fa1 ON f.id = fa1.film_id
INNER JOIN Ambiences AS a1 ON a1.id = fa1.ambience_id
INNER JOIN Films_Ambiences as fa2 ON f.id = fa2.film_id
INNER JOIN Ambiences AS a2 ON a2.id = fa2.ambience_id
INNER JOIN Films_Ambiences as fa3 ON f.id = fa3.film_id
INNER JOIN Ambiences AS a3 ON a3.id = fa3.ambience_id
INNER JOIN Films_Ambiences AS fa_all ON f.id = fa_all.film_id
INNER JOIN Ambiences AS a_all ON a_all.id = fa_all.ambience_id
WHERE (a1.ambienceName, a2.ambienceName, a3.ambienceName) = ('funny','scary','bank')
GROUP BY f.id;
+----+--------------+-------------------------+
| id | Title | ambiences |
+----+--------------+-------------------------+
| 1 | Mary Poppins | funny,scary,London,bank |
| 2 | Heist | funny,scary,bank,crime |
+----+--------------+-------------------------+
順便說一句,這裏的指數的EXPLAIN顯示用法:
+----+-------------+--------+--------+----------------------+--------------+---------+-----------------------------+------+-----------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+--------+----------------------+--------------+---------+-----------------------------+------+-----------------------------------------------------------+
| 1 | SIMPLE | a1 | ref | PRIMARY,ambienceName | ambienceName | 258 | const | 1 | Using where; Using index; Using temporary; Using filesort |
| 1 | SIMPLE | a2 | ref | PRIMARY,ambienceName | ambienceName | 258 | const | 1 | Using where; Using index |
| 1 | SIMPLE | a3 | ref | PRIMARY,ambienceName | ambienceName | 258 | const | 1 | Using where; Using index |
| 1 | SIMPLE | fa1 | ref | PRIMARY,ambience_id | ambience_id | 4 | test.a1.id | 1 | Using index |
| 1 | SIMPLE | f | eq_ref | PRIMARY | PRIMARY | 4 | test.fa1.film_id | 1 | NULL |
| 1 | SIMPLE | fa2 | eq_ref | PRIMARY,ambience_id | PRIMARY | 8 | test.fa1.film_id,test.a2.id | 1 | Using index |
| 1 | SIMPLE | fa3 | eq_ref | PRIMARY,ambience_id | PRIMARY | 8 | test.fa1.film_id,test.a3.id | 1 | Using index |
| 1 | SIMPLE | fa_all | ref | PRIMARY,ambience_id | PRIMARY | 4 | test.fa1.film_id | 1 | Using index |
| 1 | SIMPLE | a_all | eq_ref | PRIMARY | PRIMARY | 4 | test.fa_all.ambience_id | 1 | NULL |
+----+-------------+--------+--------+----------------------+--------------+---------+-----------------------------+------+-----------------------------------------------------------+
我有一個FILM1這是可怕的,搞笑的,笨。當我搜索一部只有可怕的電影時,我會無論如何都會拍電影。如果我不想要那個怎麼辦?
噢,好吧,我完全不明白這就是你的意思,這是對這些類型的問題的一個不尋常的要求。
這裏有一個解決方案:
mysql> SELECT f.*, GROUP_CONCAT(a_all.ambienceName) AS ambiences
FROM Films AS f
INNER JOIN Films_Ambiences as fa1 ON f.id = fa1.film_id
INNER JOIN Ambiences AS a1 ON a1.id = fa1.ambience_id
INNER JOIN Films_Ambiences as fa2 ON f.id = fa2.film_id
INNER JOIN Ambiences AS a2 ON a2.id = fa2.ambience_id
INNER JOIN Films_Ambiences AS fa_all ON f.id = fa_all.film_id
WHERE (a1.ambienceName, a2.ambienceName) = ('scary','stupid')
GROUP BY f.id
HAVING COUNT(*) = 2
+----+-------+--------------+
| id | Title | ambiences |
+----+-------+--------------+
| 5 | Signs | scary,stupid |
+----+-------+--------------+
有沒有必要加入到a_all
在這種情況下,因爲我們不需要氛圍名稱的列表,我們只需要氛圍的數量,我們可以得到只需加入fa_all
即可。
即使您知道環境的數量,您的查詢也不正確。單一的氛圍無法同時兼顧傷感和趣味。 – Barmar
並沒有列'a.ambiences'。 – Barmar
我的意思是隻是氛圍,我相信。編輯。 – Sharkz