Invantive SQLは、技術的な仕組みを裏側に隠すことで、データの一括更新や同期を簡単に行えるようにします。update文および/またはsynchronize文を使えば、すべての業務プロセスが同じデータを使用するように、クラウドアプリケーション内のデータを簡単に一括更新できます。
一部のクラウドアプリケーションでは、技術的理由、フェアユース、あるいは商業的な理由からAPI呼び出しの回数に制限を設けています。この制限を超えると、「Too many requests」といったエラーメッセージやHTTPステータスコード429が返されることがよくあります。
このようなAPI呼び出し数の制限は、一般的に「レート制限(rate limit)」と呼ばれます。日単位、月単位、分単位、API単位、API操作単位(読み取り/書き込み)、あるいはAPI結果単位(エラーの有無を問わず)など、複数のレート制限が同時に適用されることもあります。
多くの場合、追加のAPI呼び出しを購入することでレート制限を引き上げることができ、前払いまたは後払いでの精算が選べます。プラットフォームによっては、API呼び出しのレート制限の引き上げが比較的高額で、複雑な呼び出しの場合には1件あたり数十ユーロに達することもあれば、逆に非常に安価なプラットフォームもあります。
月や日のように時間単位ごとに回数が制限されている場合は、利用可能なレート制限の枠を適切なタイミングで使うことが賢明です。優先度の低い変更は期間の終わりに実行することで、クラウドプラットフォームへの投資から最大限の効果を得られます。
API呼び出し回数を時間的に調整するのは、まずAPI呼び出し回数そのものを制限した後に行ってください。機能面でのヒントはHoe plan ik mijn Exact Online-omgeving op het beschikbare aantal API-calls? を、技術面でのヒントはたとえばSnel en met minder API-calls Exact Online uitlezen met de incrementele "sync API"-tabellen をご覧ください。
Invantive SQLは、利用可能なレート制限の枠をできるだけ効果的に使うための機能を備えています。ほとんどのプラットフォームでは、データディクショナリービューSystemPartitions@DataDictionaryの列にこの利用可能な枠が表示されます。ここには、日・時間・分単位のレート制限、および当日・当時間・当分内のリクエスト数を示す列が含まれています。
synchronize文では、最大でいくつの変更を行うかを指定できます。これは従来のupdate文、delete文、insert文でも同様に可能です。
update、delete、insertの最大変更件数は、select文でlimitが選択結果の行数を制限するのと同様に、limit 件数で設定できます。
Exact Online APIを用いた実際のケースを基に、これを説明します。
ケーススタディ:請求書添付ファイルの変更
Exact Onlineの会計システムでは、管理環境ごとに取引先単位で、請求書をどの形式で送付するかを設定できます。これは複数の形式を組み合わせることができ、いわゆる「ビット単位のAND(bitwise AND)」によって一つの数値にまとめられます。たとえば値「1」は売上請求書をPDF形式のみで送付することを意味し、値「2」はUBL形式、値「3」はPDF形式とUBL形式の両方を意味します。
それぞれ5万件の取引先を抱える管理環境を持つExact Onlineデータベースにおいて、すべての管理環境で請求書添付ファイルの形式をPDF+UBLからPDFのみに変更する必要があります。しかし、Exact OnlineにおけるAPI呼び出しの1日あたりの回数は、必要な5万回のAPI呼び出しのごく一部に過ぎず、しかもこの変換作業は日次処理よりも優先度が低いものです。
そのため、1日の終わりにこれらの変更をExact Onlineに反映させ、この追加リクエストによって残っているAPI呼び出し予算を消費させるようにします。
この変更の中で最も優先度が高いのは販売顧客に対するものであり、それ以外の取引先はまだ顧客ステータスを持っていません。
このジョブでは、Exact Onlineに対する変更件数を次のupdate文によって10件に制限できます。
use SELECTIE_ADMINISTRATIES@eol
update exactonlinerest..accounts@eol
set InvoiceAttachmentType = 1
where InvoiceAttachmentType = 3
and status = 'C'
limit 100
ここでは、Exact OnlineのテーブルAccountsIncrementalは使用していません。このテーブルは読み取り専用であり、より複雑なsynchronize文が必要になります。一方、where句はInvantiveのサーバーサイドフィルタリングとExact Onlineのフィルター機能によって、そのままExact Onlineに渡すことができるため、更新対象の行を取得するのに必要なExact OnlineへのAPI呼び出しはわずか1回で済みます。
この文は、変更が必要な顧客がまだ残っている場合でも、およそ3秒ほどで完了します。
残っているAPI呼び出し予算があれば、顧客ではない取引先についても請求書添付ファイルの種類を設定するために使うことができます。
use SELECTIE_ADMINISTRATIES@eol
update exactonlinerest..accounts@eol
set InvoiceAttachmentType = 1
where InvoiceAttachmentType = 3
limit 100
改良:複数の管理環境への対応
この一括変更は、複数の管理環境にも簡単に拡張できます。そのためには、まず管理環境の選択を指定します。たとえばすべてのExact Online管理環境を対象にする場合は次のようになります。
use all@eol
update exactonlinerest..accounts@eol
set InvoiceAttachmentType = 1
where InvoiceAttachmentType = 3
and status = 'C'
limit 1000
update exactonlinerest..accounts@eol
set InvoiceAttachmentType = 1
where InvoiceAttachmentType = 3
limit 1000
Exact Onlineでは現在、API呼び出しの制限が管理環境ごとに適用されているため、この制限をより高く設定することが可能です。この例では10件の管理環境を想定しており、並列処理によって1000件の更新がおおよそ10件の管理環境全体に分散されます。ただし、管理環境ごとに必要なAPI更新の量が大きく異なる場合はこの限りではありません。
改良:できるだけ短時間での空きAPI呼び出し枠の活用
さらに高度な改良としては、API呼び出しの回数をその管理環境で利用可能な分だけに制限しつつ、(並列化を行わずに)処理時間を最小限に抑える方法があります。
次のInvantive PSQLのブロックは、短い一連の更新を繰り返し実行するもので、Exact Onlineの1分あたり60回というAPI呼び出しの分間制限をできるだけ早く使い切るように長さが調整されています。
declare
l_did_work boolean;
l_dummy_cnt number;
g_max_call_per_minute pls_integer := 50 /* より頻繁に切り替えられるよう、60よりやや低い値に設定。 */;
begin
use all@eol;
--
-- 残りのAPI呼び出し数が最新になるよう、
-- すべての管理環境に一度アクセスする。
--
select /*+ http_disk_cache(false) http_memory_cache(false) */ count(*)
into l_dummy_cnt
from exactonlinerest..journals@eol
;
l_did_work := true;
while l_did_work
loop
dbms_output.put_line('1分間、各管理環境のAPI呼び出し分間制限に到達するよう試みる。');
l_did_work := false;
for r
in
( select 'update exactonlinerest..accounts@eol'
|| ' set InvoiceAttachmentType = 1'
|| ' where InvoiceAttachmentType = 3'
|| ' limit '
|| to_char
( case
when DAILY_REMAINING > g_max_call_per_minute
then g_max_call_per_minute
else DAILY_REMAINING
--
-- 本日後ほど発生する可能性のある予期しない優先タスクのために、
-- Exact OnlineのAPI呼び出しを500回分残しておく。
--
- 500
end
)
stmt
, '最大'
|| g_max_call_per_minute
|| '行を管理環境 '
|| code
|| ' - '
|| name
|| ' で更新する'
txt
from SYSTEMPARTITIONS@DataDictionary
where IS_SELECTED = true
and PROVIDER_NAME = 'ExactOnlineAll'
and PROVIDER_DATA_CONTAINER_ALIAS = 'eol'
--
-- 本日、この管理環境に対してAPI呼び出しが
-- 少なくとも500回残っている必要がある。
--
and DAILY_REMAINING > 500
)
loop
dbms_output.put_line(r.txt);
execute immediate r.stmt;
l_did_work := true;
end loop;
end loop;
end;