Sql 使用两个字段排序时,DB2 ORDER BY查询速度较慢
我有一个DB2表,它具有以下模式:Sql 使用两个字段排序时,DB2 ORDER BY查询速度较慢,sql,performance,select,db2,sql-order-by,Sql,Performance,Select,Db2,Sql Order By,我有一个DB2表,它具有以下模式: CREATE TABLE "CONTACTS" ( "ID" CHAR(36) NOT NULL, "DELETED" SMALLINT DEFAULT 0, "FIRST_NAME" VARCHAR(200), "LAST_NAME" VARCHAR(200) ); CREATE INDEX "IDX_CONTACTS_DEL_LAST" ON "CONTACTS" ("DELETED" ASC, "LA
CREATE TABLE "CONTACTS" (
"ID" CHAR(36) NOT NULL,
"DELETED" SMALLINT DEFAULT 0,
"FIRST_NAME" VARCHAR(200),
"LAST_NAME" VARCHAR(200)
);
CREATE INDEX "IDX_CONTACTS_DEL_LAST" ON "CONTACTS"
("DELETED" ASC,
"LAST_NAME" ASC)
MINPCTUSED 0 ALLOW REVERSE SCANS PAGE SPLIT SYMMETRIC COMPRESS YES;
CREATE INDEX "IDX_CONTACT_LASTNAME" ON "CONTACTS"
("LAST_NAME" ASC,
"DELETED" ASC)
MINPCTUSED 0 ALLOW REVERSE SCANS PAGE SPLIT SYMMETRIC COMPRESS YES;
CREATE INDEX "IDX_CONT_LAST_FIRST" ON "CONTACTS"
("LAST_NAME" ASC,
"FIRST_NAME" ASC,
"DELETED" ASC)
MINPCTUSED 0 ALLOW REVERSE SCANS PAGE SPLIT SYMMETRIC COMPRESS YES;
CREATE INDEX "IDX_ID_DEL" ON "CONTACTS"
("ID" ASC,
"DELETED" ASC)
MINPCTUSED 0 ALLOW REVERSE SCANS PAGE SPLIT SYMMETRIC COMPRESS YES;
CREATE UNIQUE INDEX "CONTACTSPK" ON "CONTACTS"
("ID" ASC)
MINPCTUSED 0 ALLOW REVERSE SCANS PAGE SPLIT SYMMETRIC COMPRESS YES;
ALTER TABLE "CONTACTS" ADD CONSTRAINT "CONTACTSPK" PRIMARY KEY ("ID");
此查询工作正常(快速):
但是,在相当大(数百万行)的数据库上,速度几乎慢1000倍:
SELECT * FROM (SELECT contacts.id, contacts.first_name, contacts.last_name
FROM contacts WHERE contacts.deleted=0
ORDER BY contacts.last_name ASC, contacts.id ASC)
LIMIT 21 OPTIMIZE FOR 21 ROWS
现在,我假设oncelast\u name
被编入索引并具有足够的基数(确实如此),添加二级排序应该无关紧要。然而,事实证明这很重要——它使查询速度慢了一千倍。我的问题是,为什么DB2不应该只从last\u name/deleted
索引中取前21行,这应该非常快,按ID
对它们进行排序,然后处理它?然而,它看起来做了全表扫描,或者至少做了一些非常昂贵的事情。所以我的问题是为什么
第二个问题是,是否有一种方法可以添加二级排序字段而不会造成这种影响。原因是由于将字段添加到
联系人中
他们将有自己的索引,但将id
添加到每个索引中看起来很浪费。当然,有些字段可能有许多记录具有相同的姓氏
或其他值,因此为这些行设置稳定的顺序非常有用,尤其是在分页时。DB2是否保证这样的顺序而不进行二次排序?您想要的索引位于联系人(已删除,姓氏,id)
上。这将使用lastname
作为排序键以及lastname
和id
对查询起作用
性能问题的原因。首先,仅使用lastname
的快速查询使用索引。另一个可以使用索引,也可以不使用索引,但它必须获取具有相同lastname
的所有行,然后必须按id
对它们进行排序。毕竟,没有理由认为索引中具有相同lastname
的前21行都具有相同的id
这个问题可能是两件事之一。第一个问题是,一个姓氏可能有许多具有相同id
的记录。第二个原因很简单,DB2因为存在id
而感到困惑,并决定不使用索引
虽然它可能对查询没有帮助,但如果确实是主键,则应该将
id
声明为主键。我查看了实际数据,虽然有一些记录具有相同的姓氏,但它们并不多,每个名称不超过2-3个。不应导致1000倍的减速。因此,出于某种原因,DB2似乎放弃了索引进行二次排序。也许您可以从查看两个查询的EXPLAIN
输出开始?@IanBjorhovde不幸的是,EXPLAIN显示速度慢的查询不使用索引,但它无法解释为什么不使用索引以及如何使用索引。
SELECT * FROM (SELECT contacts.id, contacts.first_name, contacts.last_name
FROM contacts WHERE contacts.deleted=0
ORDER BY contacts.last_name ASC, contacts.id ASC)
LIMIT 21 OPTIMIZE FOR 21 ROWS