我在书籍和流派之间有多对多的关系。例如"霍比特人"书可能有类型"孩子","小说"和#34;幻想"。
这是架构:
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");
行数:
我正在尝试在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),因此可以添加视图,索引或非规范化。我也在使用Django,因此可以使用Python / Django执行多个查询在内存中执行操作。
答案 0 :(得分:3)
SELECT b.name, b.price
FROM book b
WHERE EXISTS (
SELECT *
FROM book_genres bg
WHERE bg.book_id = b.id
AND bg.genre_id IN( 1 , 2)
)
ORDER BY b.price
LIMIT 10
;
按价格排序+ LIMIT可能是性能杀手:检查查询计划。
PLUS:将一列索引替换为"反转"指数: 把book_id变成了书籍 并且(可能)省略代理键id
CREATE TABLE book_genres
( book_id integer NOT NULL REFERENCES book (id)
, genre_id integer NOT NULL REFERENCES genre (id)
, PRIMARY KEY (book_id, genre_id)
) ;
CREATE INDEX ON book_genres (genre_id,book_id);
答案 1 :(得分:2)
在大多数情况下,您可以使用JOIN
而不是子查询来提高性能(虽然这取决于很多因素):
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