jfluteです
ありがとうございます。
ということは、そのスーパークラスの SimplePagingBean ですね。
コードも読んで原因わかりました。
もともと、SQLServer は、row_number() がなく、
top構文 (limit) のみでのページングしかできませんでした。
ゆえに、ConditionBeanではoffsetでカーソルスキップを利用し、
外だしSQLでも AutoPaging だろうが ManualPaging だろうが、
offset 部分に関してはカーソルスキップが必要でした。
そう、ManualPagingでもカーソルスキップが必要なので、
SQLServerの場合は、ManualPagingでもカーソルスキップになるようにしていました。
実はそれが今回の現象です。
SQLとしては、top構文を使ったページングを行い、
ManualPaging を選ぶと、offsetはカーソルスキップで実現、limitはtop構文で実現、
というようになります。
外だしSQLなのに FetchNarrowingResultSetWrapper が使われるのはおかしいな、
というところでしたが、DBFlute.NETのSQLServer対応においてはそれが正しい挙動でした。
ただ、SQLServerのバージョンが上がり、row_number()関数が使えるようになりました。
で、Java版のDBFluteにおいては、外だしSQLのManualPagingを書くときはtop構文は使わず、
row_number()関数を使ってやりましょう、ということでフレームワークもドキュメントも
修正されています。(ただ、ConditionBeanは実装コストの都合でtop構文のままです)
ですが、DBFlute.NETの方は、上記のtop構文で外だしSQLのManualPagingを行うことが前提で、
今も実装されている状態です。.NETの方は、SQLServer2000が根強く利用され続けていたので、
そのままtop構文メインでの方式を維持していたというところです。
その状態で、今回は row_number() を使って外だしSQLを書かれているので、
そこでギャップが生まれてしまいました。
row_number() でも10件スキップしているのに、カーソルスキップでも10件スキップするので、
10件目から20件目のデータがまるごとカーソルスキップで無くなってしまうと。
(なので、MySQLやOracleでは発生しない現象です)
そういうことで、回避策としては...
A. top構文で書く
- カーソルスキップに頼ることになりますが、パフォーマンス激劣化するわけじゃない
- フレームワークをいじらずに回避できる (いまのDBFlute.NETが想定している実装に)
B. SimplePagingBean.vmnet をいじる
- Java版に少しだけ近い実装をして、SQLServerでもカーソルスキップしないManualPagingに
- フレームワークをいじることになる (パッチを当てるような感じ)
108 public bool IsFetchNarrowingEffective { get { return
this.SqlClause.isFetchNarrowingEffective(); } }
109 public void IgnoreFetchNarrowing() { _fetchNarrowing = false; }
110 public void RestoreIgnoredFetchNarrowing() {
_fetchNarrowing = true; }
↓↓↓ (108行目に_fetchNarrowingの判定をand条件で追加)
108 public bool IsFetchNarrowingEffective { get { return
_fetchNarrowing && this.SqlClause.isFetchNarrowingEffective(); } }
109 public void IgnoreFetchNarrowing() { _fetchNarrowing = false; }
110 public void RestoreIgnoredFetchNarrowing() {
_fetchNarrowing = true; }
Java版のSimplePagingBean.javaがそのようになっています。
https://github.com/dbflute/dbflute-core/blob/master/dbflute-runtime/src/main/java/org/dbflute/outsidesql/paging/SimplePagingBean.java#L291
別の箇所で、ManualPagingのときはこれが false になるようにセットされるので、
IsFetchNarrowingEffective が固定的に false になります。
すると、FetchNarrowingResultSetFactory の IsUseFetchNarrowingResultSetWrapper() は、
IsFetchNarrowingEffective() を使った分岐で false になるので、Wrapper は利用されません。
上記の修正をしても、ConditionBeanはSimplePagingBeanとは何も関わらないので影響ないはずで、
AutoPagingのときは、_fetchNarrowing が false にならないので、大丈夫なはずです。
(はず、というのは一度ちゃんと確認してみないと、という感じです)
色々と検証ありがとうございました。
なかなかDBFlute.NETのジレンマな部分で申し訳ないですが、
ひとまず、このような状況です。