开发者

Fastest most/efficient way to do pagination with SQL searching DB2

Right now I do two separate SQL statements, one doing a SELECT COUNT(*) on basically the same criteria as the search statement. I am not the best at making these statements and sometimes are a little slow and I would like to know if there is a better way to be doing what I do. Possibly doing only one SQL statement and some more work in PHP? Here is an example "search contains" I have the statements for.

On the second statement you will see the X between Y, that's partially calculated by the result from the first row count statement.

SQL Row Count:

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 Search:

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


If you're trying to display a total count of the results alongside the paginated counts (so '0 to 25 out of 38), a separate statement may be your best bet. I've tried a number of things to get the counts alongside the individual rows, but the performance (even over a moderate test database) is terrible.

What you probably ought to do is create a view you can query against, which contains all your selection criteria, then just wrap it with the necessary behaviour:
Count:

SELECT COUNT(*)
FROM view

Ranked rows:

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

You will of course need to add the relative where conditions, but this is the type of thing views are meant to handle.

If you don't actually need to know the total rows ahead of time, you can simply set the end-rank as the start-rank plus some offset. Then, when you display your results with PHP, simply edit the ending display value.

Some random notes: 1) Is there are reason that line isn't upper()d?
2) The performance of this query is going to suffer almost no matter what you do, simply because of all the string manipulation/comparisons. Is it possible to eliminate or ignore some of the conditions? Unless the indicies used over the various string columns have had upper applied to them (some later versions of DB2 allow certain scalar functions to be applied to the index key), most indicies are going to be completely useless (it doesn't help that you're looking for %ANYTHING% after all).


Okay, there is a 'tricky' way to do something like this, and seems to get okay performance... Try something like this (a view defined first will really help):

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

Of course, you'll still have to have your where clause defined in the subselect too...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜