我在DB2-Database中有两个巨大的表。我已经将实名改编为另一个问题,以突出问题并混淆真实用例。
CREATE TABLE Author (
id integer PRIMARY KEY NOT NULL,
name vargraphic(32) NOT NULL,
country vargraphic(32) NOT NULL)
CREATE TABLE Book(
id integer PRIMARY KEY NOT NULL,
title vargraphic(32) NOT NULL,
authorId INTEGER NOT NULL REFERENCES Author(id),
releaseYear Integer NOT NULL)
两个表都变得如此之大,以至于在其中任何一个表上执行全表扫描都是不可行的。
在这里,我想找到2017年发布的前10本书,按其标题排序
SELECT b.title, b.authorId
FROM Book b
WHERE b.RELEASEYEAR = 2017
ORDER BY b.TITLE
FETCH FIRST 10 ROWS ONLY
为了加快速度,我创建了一个索引
CREATE INDEX itest1 ON BOOK (releaseYear, title, id, authorid);
使用此索引完成仅索引扫描并且查询非常快。
现在我想把结果限制在美国作家写的那些书中。
SELECT b.title, b.authorId
FROM Book b
JOIN Author a ON (a.id = b.authorId)
WHERE b.RELEASEYEAR = 2017
AND a.COUNTRY = 'USA'
ORDER BY b.TITLE
FETCH FIRST 10 ROWS ONLY
我尝试通过添加更多索引来加快此查询:
CREATE INDEX itest3 ON AUTHOR (id, country);
CREATE INDEX itest4 ON AUTHOR (country, id);
即使使用严格的仅索引扫描,性能也不会与前一个声明的性能接近。
EXPLAIN PLAN告诉我,在对两个表进行索引扫描后,就完成了一个昂贵的嵌套循环连接。似乎第一个索引用于从2017年查找书籍,按标题排序,第二个索引用于作者按国家/地区。但是如果每个子集仍然很大,那么创建交集需要很长时间。
我想做的是通过使用跨越两个表的单个索引来避免嵌套循环。
CREATE INDEX two_table_index ON Book b JOIN Author a (a.country, b.releaseYear, b.title)
但这似乎不太可能。是否有另一种方法可以在非常大的表上有效地运行第二个查询?
答案 0 :(得分:1)
我怀疑你只使用索引会变得更好,如果你真的希望这个查询非常快,你必须将国家复制到book表中,然后使用两个索引:
索引一位作者(id)(关键我猜?)
索引两本书(发布年份,作者,作者)
答案 1 :(得分:1)
EXPLAIN PLAN告诉我,在对两个表进行索引扫描后,就完成了一个昂贵的嵌套循环连接。似乎第一个索引用于查找2017年的书籍,按标题排序,第二个索引按国家/地区用于作者。但是如果每个子集仍然很大,那么创建交集需要很长时间。
当然,它正在做什么;这是你允许它做的所有指数。
问题本质上是Book
上唯一的索引,它不会帮助它缩小作者的范围,直到排序步骤中或之后; title
是索引中的死列。通常,过滤条件应首先出现在索引中,并且连接计为一个。
尝试以下一个(或多个)索引:
-- More generally applicable
BOOK (authorId, releaseYear, title)
-- This one might help more for this query
BOOK (releaseYear, authorId, title)
-- Won't help at all for this query, but probably useful for others
BOOK (authorId, title)
作为旁注:大多数时候优化器会为查询吐出推荐的索引,是否会列出任何?