我有书籍和流派之间的多对多关系。例如,“霍比特人”的书可能有流派“孩子”,“小说”和“幻想”。如何提高多对多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