【问题标题】:Fastest most/efficient way to do pagination with SQL searching DB2使用 SQL 搜索 DB2 进行分页的最快最有效方法
【发布时间】:2011-10-23 07:03:02
【问题描述】:

现在我执行两个单独的 SQL 语句,一个执行 SELECT COUNT(*),其条件与搜索语句基本相同。我不是最擅长做这些陈述,有时有点慢,我想知道是否有更好的方法来做我所做的事情。可能只做一个 SQL 语句,而在 PHP 中做更多的工作?这是一个示例“搜索包含”我有语句。

在第二个语句中,您将看到 Y 之间的 X,这部分是由第一个行计数语句的结果计算得出的。

SQL 行数:

SELECT COUNT(*) 
FROM itemmast 
LEFT OUTER JOIN itemweb 
ON iline = line 
AND iitem = item 
JOIN linemst 
ON iline = lline 
LEFT OUTER JOIN custord 
ON opline = iline 
AND opitem = iitem 
AND opcust = '12345' 
LEFT OUTER JOIN ordwdtl 
ON owline = iline 
AND owitem = iitem 
AND owusr ='user' 
AND owcust ='12345' 
WHERE ico = 01 
AND iecomm = 'Y'  
AND (UPPER(ITEMDESC) || UPPER(PRODDESC)) LIKE '%FOO%' 
     OR LINE LIKE '%FOO%' 
     OR UPPER(MFGNAME) LIKE '%FOO%' 
     OR UPPER(ITEM) LIKE '%FOO%' 
     OR UPPER(PRODNAME) LIKE '%FOO%' 
     OR UPPER(IDESC1 || IDESC2) LIKE '%FOO%' 
     OR UPPER(IMFGNO) LIKE '%FOO%' 
     OR UPPER(IITEM) LIKE '%FOO%') 

SQL 搜索:

SELECT * 
FROM (SELECT iline AS line, iitem AS item, rownumber() OVER (ORDER BY item) AS ROW_NUM 
      FROM itemmast 
      LEFT OUTER JOIN itemweb 
      ON iline = line 
      AND iitem = item 
      JOIN linemst 
      ON iline = lline 
      LEFT OUTER JOIN custord 
      ON opline = iline 
      AND opitem = iitem 
      AND opcust = '12345' 
      LEFT OUTER JOIN ordwdtl 
      ON owline = iline 
      AND owitem = iitem 
      AND owusr = 'user' 
      AND owcust = '12345' 
      WHERE ico = 01 
      AND iecomm = 'Y' 
      AND (UPPER(ITEMDESC) || UPPER(PRODDESC)) LIKE '%FOO%' 
           OR LINE LIKE '%FOO%' 
           OR UPPER(MFGNAME) LIKE '%FOO%' 
           OR UPPER(ITEM) LIKE '%FOO%' 
           OR UPPER(PRODNAME) LIKE '%FOO%' 
           OR UPPER(IDESC1 || IDESC2) LIKE '%FOO%' 
           OR UPPER(IMFGNO) LIKE '%FOO%' 
           OR UPPER(IITEM) LIKE '%FOO%')) 
      AS TEMP 
WHERE ROW_NUM BETWEEN 0 AND 25

【问题讨论】:

    标签: php sql pagination db2


    【解决方案1】:

    如果您尝试在分页计数旁边显示结果的总计数(因此 38 中的 0 到 25),单独的语句可能是您的最佳选择。我已经尝试了很多方法来获取各个行旁边的计数,但是性能(即使在中等测试数据库上)很糟糕。

    您可能应该做的是创建一个可以查询的视图,其中包含您的所有选择条件,然后用必要的行为包装它:
    计数:

    SELECT COUNT(*)
    FROM view
    

    排名行:

    SELECT *
    FROM (SELECT *, ROW_NUMBER() OVER(ORDER BY item) as RANK
          FROM view) as TEMP
    WHERE RANK BETWEEN 0 AND 25
    

    您当然需要添加相对的 where 条件,但这是视图要处理的事物类型。

    如果您实际上不需要提前知道总行数,您可以简单地将 end-rank 设置为 start-rank 加上一些偏移量。然后,当您使用 PHP 显示结果时,只需编辑结束显示值。

    一些随机笔记: 1) line 不是 upper()d 有什么原因吗?
    2)这个查询的性能几乎无论你做什么都会受到影响,仅仅是因为所有的字符串操作/比较。是否可以消除或忽略某些条件?除非在各种字符串列上使用的索引已经应用了upper(DB2 的一些更高版本允许将某些标量函数应用于索引键),否则大多数索引将完全无用(它没有帮助毕竟你正在寻找%ANYTHING%)。


    好的,有一种“棘手”的方法可以做这样的事情,而且似乎性能还不错...... 尝试这样的事情(首先定义的视图会很有帮助):

    SELECT TEMP.*, CASE WHEN RANK = 0 THEN (SELECT COUNT(*)
                                            FROM view)
                        ELSE 0 END
    FROM (SELECT *, ROW_NUMBER() OVER(ORDER BY item) as RANK
          FROM view) as TEMP
    WHERE RANK BETWEEN 0 AND 25
    

    当然,您仍然必须在子选择中定义 where 子句...

    【讨论】:

    • 首先,感谢您冗长而详细的回复。我认为 line 不是 upper() 的原因是因为它已经存储为 upper() 并且不需要转换。我将检查其他字段是否是这种情况,看看是否可以删除 upper() 并查看是否也有帮助。我必须与其他人讨论这些观点,他们比我更擅长这方面的专家。这是我编写的第一批生成的 SQL 语句之一,所以这就是为什么它有点混乱:)
    • 不会太乱。尽管您可能希望删除字符串连接并仅删除 upper() 列。
    猜你喜欢
    • 1970-01-01
    • 2014-01-22
    • 2011-02-23
    • 2010-09-20
    • 1970-01-01
    • 2011-03-05
    • 1970-01-01
    • 2012-03-24
    • 2014-03-04
    相关资源
    最近更新 更多