使用按两个字段排序时,DB2 ORDER BY查询速度很慢

时间:2014-05-14 23:51:43

标签: 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, 
     "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");

此查询正常(快速):

SELECT * FROM (SELECT contacts.id, contacts.first_name, contacts.last_name 
  FROM contacts WHERE contacts.deleted=0 
ORDER BY contacts.last_name ASC) 
LIMIT 21 OPTIMIZE FOR 21 ROWS

然而,在大小(数百万行)数据库上,这几乎慢了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

现在,我假设一旦last_name被编入索引并且具有足够的基数(它确实如此),添加二级排序应该无关紧要。然而,事实证明它很重要 - 它使查询慢了一千倍。我的问题是为什么 - 不应该只从DB2 last_name/deleted索引前21行,这应该非常快,按ID排序然后用它完成?然而,它看起来它是全表扫描或至少是非常昂贵的东西。所以我的问题是为什么?

第二个问题是,是否有办法添加辅助排序字段而不会产生这种影响。原因是因为字段将被添加到contacts它们将拥有其索引,但向每个索引添加id看起来很浪费。 OTOH,某些字段可以包含大量具有相同last_name或其他值的记录,因此对这些行具有稳定的顺序非常有用,尤其是在分页时。 DB2是否在没有二次排序的情况下保证这样的顺序?

1 个答案:

答案 0 :(得分:1)

您想要的索引位于contacts(deleted, lastname, id)。这将仅适用于lastname作为排序键以及lastnameid的查询。

性能问题的原因。首先,仅使用lastname的快速查询使用索引。另一个可能会也可能不会使用索引,但它必须使用相同的lastname来获取所有行。然后它必须按id对它们进行排序。毕竟,没有理由认为具有相同lastname的索引中的前21行都具有相同的id

问题可能是两件事之一。首先,一个姓氏可能有许多具有相同id的记录。第二个原因是DB2因为id的存在而感到困惑,并决定不使用索引。

虽然它可能对查询没有帮助,但如果确实是{1},则应将id声明为主键。