【问题标题】:DB2 ORDER BY query slow when using sort by two fields使用按两个字段排序时,DB2 ORDER BY 查询很慢
【发布时间】:2014-05-14 23:51:43
【问题描述】:

我有一个具有以下模式的 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 是否保证这样的顺序没有二次排序?

【问题讨论】:

  • 也许您可以先查看EXPLAIN 的两个查询的输出?
  • @IanBjorhovde 不幸的是,虽然 EXPLAIN 显示慢速不使用索引,但它没有解释为什么不使用索引以及如何使用索引。

标签: sql performance select db2 sql-order-by


【解决方案1】:

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

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

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

虽然它可能对查询没有帮助,但您应该将 id 声明为主键,如果它确实是一个主键。

【讨论】:

  • 我查看了实际数据,虽然有一些姓氏相同的记录,但数量并不多——每个名字不超过 2-3 个。不应导致 1000 倍减速。所以看起来 DB2 出于某种原因放弃了二级排序的索引。
猜你喜欢
  • 2019-09-12
  • 1970-01-01
  • 2010-10-27
  • 2017-07-13
  • 1970-01-01
  • 2011-05-25
  • 2020-05-15
  • 1970-01-01
  • 2023-03-21
相关资源
最近更新 更多