我有書籍和流派之間的多對多關係。例如,「霍比特人」的書可能有流派「孩子」,「小說」和「幻想」。如何提高多對多SQL查詢的性能?
這裏的模式:
CREATE TABLE "genre" (
"id" integer NOT NULL PRIMARY KEY,
"name" varchar(50) NOT NULL
)
;
CREATE TABLE "book_genres" (
"book_id" integer NOT NULL REFERENCES "book" ("id"),
"genre_id" integer NOT NULL REFERENCES "genre" ("id"),
CONSTRAINT book_genres_pkey PRIMARY KEY (book_id, genre_id)
)
;
CREATE TABLE "book" (
"id" integer NOT NULL PRIMARY KEY,
"name" varchar(255) NOT NULL,
"price" real NOT NULL
)
;
而且指標:
CREATE INDEX "book_genres_36c249d7" ON "book_genres" ("book_id");
CREATE INDEX "book_genres_33e6008b" ON "book_genres" ("genre_id");
CREATE INDEX "book_5a5255da" ON "book" ("price");
行數:
- 流派:30
- book_genres 80萬
- 書:200 ,0 00
我正在嘗試在SQL中編寫一個查詢,該查詢將按照價格排序的所有書籍帶回所有書籍而不重複。
這裏是我的查詢其做到這一點:
SELECT name, price
FROM book
WHERE book.id
IN
(SELECT book_id
FROM book_genres
WHERE genre_id = 1
OR genre_id = 2)
ORDER BY price LIMIT 10
我的問題是性能。該查詢最多可能需要2000毫秒才能執行。我怎樣才能提高性能?
我完全控制數據庫(Postgres 9.3),所以可以添加視圖,索引或denormalise。我也使用Django,因此可以使用Python/Django執行多個查詢在內存中執行操作。按價格+ LIMIT
SELECT *
FROM
(
SELECT b.name, b.price
FROM book b JOIN book_genres g ON b.book.id = g.book_id
AND g.genre_id = 1
UNION
SELECT b.name, b.price
FROM book b JOIN book_genres g ON b.book.id = g.book_id
AND g.genre_id = 2
)
ORDER BY price LIMIT 10
謝謝,我已經做出了您所建議的更改。性能與我當前的查詢相同。需要注意的一點是,使用'OFFSET'(例如'OFFSET 500'),性能會進一步惡化。計劃者輸出是否有幫助? – donturner
(你在表格修改之後做了真空分析?)刪除'按價格LIMIT xxx'的順序,性能可能會變好(如果沒有太多的行滿足您的條件)OFFSET可能會使事情變得更糟。 – joop
「你做過真空分析嗎?」 - 這是問題!我沒有運行過。現在,我的原始查詢每次不使用「OFFSET」時會運行小於20毫秒,並且在使用時最多可以運行200毫秒(這是可以接受的)。非常棒的工作,感謝您指點我的解決方案。 – donturner