ぱと隊長日誌

ブログ運用もエンジニアとしての生き方も模索中

SELECT-INSERT で SELECT に ORDER BY を指定するとソートが実行される

概要

SQL では SELECT した結果を INSERT できます(本記事では SELECT-INSERT と呼称します)。また、SELECT-INSERT の SELECT には ORDER BY を指定することもできます。リレーショナルモデルは集合を扱い、行の順序を意識しないはずです。なのになぜ SELECT-INSERT の SELECT で ORDER BY できるのか…という疑問と検証を書き留めています。

仮説

リレーショナル・データベースはリレーショナルモデルを基にしています。

リレーショナル・データベースの例として Oracle Database や PostgreSQL 等があります。

リレーショナルモデルは集合の概念と結びついています。集合の要素には順序付けがありません。数学の集合が {a,b,c} と {c,a,b} を同じものとして扱うことは、リレーショナルモデルにおいても当てはまります。

リレーショナルモデルが順序を意識しないことは ORDER BY を指定しない SELECT 結果の行の順序が不定であることにも表れています。PostgreSQL のマニュアルから該当する記載を引用します。

ある問い合わせが1つの出力テーブルを生成した後(選択リストの処理が完了した後)、並べ替えることができます。並べ替えが選ばれなかった場合、行は無規則な順序で返されます。そのような場合、実際の順序は、スキャンや結合計画の種類や、ディスク上に格納されている順序に依存します。しかし、当てにしてはいけません。明示的に並べ替え手続きを選択した場合にのみ、特定の出力順序は保証されます。

7.5. 行の並べ替え

リレーショナルモデルが順序を意識しないとすると、INSERT 時の行の順序も意味がないことになります(自動採番においては意味を持ちますが、ここでは考えないことにします)。とすれば、SELECT-INSERT の ORDER BY が意味を持たない場合はリレーショナル・データベースによって最適化され、クエリの実行時に無視されるのではないでしょうか?

検証

検証手段

「SELECT-INSERT の ORDER BY が意味を持たない場合はクエリの実行時に無視される」という仮説を検証します。

仮説を検証するため、Oracle Database 19.3 と PostgreSQL 14.1 において、実行計画を取得しました。クエリの文法として SELECT-INSERT の ORDER BY を記述できたとしても、それが意味を持たないのであればクエリの実行時に無視されるはずです。

tab1 の値を降順 (desc) でソートし、その結果を tab2 に INSERT する、という SELECT-INSERT で検証します。

Oracle Database 19.3

実行計画の取得方法については下記の記事を参考にしました。
Oracle SQL実行計画の読み方 | コーソルDatabaseエンジニアのBlog

実行したクエリは以下の内容です。

CREATE TABLE tab1(c1 INTEGER);
CREATE TABLE tab2(c1 INTEGER);

INSERT INTO tab1 SELECT rownum
  FROM (SELECT level FROM dual CONNECT BY level <= 1e+6);

SET LINESIZE 200;
SET PAGESIZE 0;

SET SERVEROUTPUT OFF;
ALTER SESSION SET statistics_level=ALL;

INSERT INTO tab2(c1) SELECT c1 FROM tab1 ORDER BY c1 desc;

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format=>'ALLSTATS LAST'));

得られた実行計画を示します。

----------------------------------------------------------------------------------------------------------------------
| Id  | Operation                | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------
|   0 | INSERT STATEMENT         |      |      1 |        |      0 |00:00:00.68 |   16307 |       |       |          |
|   1 |  LOAD TABLE CONVENTIONAL | TAB2 |      1 |        |      0 |00:00:00.68 |   16307 |       |       |          |
|   2 |   SORT ORDER BY          |      |      1 |   1033K|   1000K|00:00:00.17 |    1522 |    24M|  1794K|   21M (0)|
|   3 |    TABLE ACCESS FULL     | TAB1 |      1 |   1033K|   1000K|00:00:00.01 |    1522 |       |       |          |
----------------------------------------------------------------------------------------------------------------------

プランに "SORT ORDER BY" が現れており、ORDER BY のソート処理に時間を費やしたことが読み取れます。

PostgreSQL 14.1

実行したクエリは以下の内容です。

CREATE TABLE tab1(c1 INTEGER);
CREATE TABLE tab2(c1 INTEGER);

INSERT INTO tab1 SELECT generate_series(1, 1e+6);

EXPLAIN ANALYZE INSERT INTO tab2(c1) SELECT c1 FROM tab1 ORDER BY c1 desc;

得られた実行計画を示します。

 Insert on tab2  (cost=144571.25..158675.93 rows=0 width=0) (actual time=1113.012..1113.014 rows=0 loops=1)
   ->  Sort  (cost=144571.25..147392.18 rows=1128375 width=4) (actual time=222.429..325.495 rows=1000000 loops=1)
         Sort Key: tab1.c1 DESC
         Sort Method: external merge  Disk: 13800kB
         ->  Seq Scan on tab1  (cost=0.00..15708.75 rows=1128375 width=4) (actual time=0.031..71.985 rows=1000000 loops=1)
 Planning Time: 7.509 ms
 Execution Time: 1113.883 ms

プランに "Sort" が現れており、ORDER BY のソート処理に時間を費やしたことが読み取れます。

考察

Oracle Database 19.3 と PostgreSQL 14.1 共に ORDER BY のソート処理で時間を費やしていました。よって「SELECT-INSERT の ORDER BY が意味を持たない場合はクエリの実行時に無視される」という仮説は否定されたことになります。

不要と思える ORDER BY のソート処理を実行する設計(実装)となっている理由は分かりませんでした。

データをデータベースとして組織化した目的は、アプリケーションプログラムをデータの諸元(特に、レコードの物理的格納順、インデックスの有無、データへのアクセスパスなど)から切り離し、それらの改変と無関係とする、即ちアプリケーションプログラムのデータ独立性を達成するためであった。
リレーショナルデータベース入門―データモデル・SQL・管理システム・NoSQL (Information & Computing)
6.4 3層スキーマの意義

この記述にある通り、データベースはアプリケーションプログラムに「レコードの物理的格納順」を意識させません。また、リレーショナルモデルとしても順序を意識しないことを考えると、INSERT の順序を決めるような ORDER BY は不要な処理として最適化されるのが妥当に思えるのですが…。

今後、新たな知見を得られた際に再度調査します。

幼い子供の育児と自分の勉強時間確保の両立(3~5歳編)

きっかけ

以前にほぼ同じタイトルで記事を書きました。
幼い子供の育児と自分の勉強時間確保の両立 - ぱと隊長日誌

当時は子供がまだ1歳半の頃でしたが、今や5歳です。時が経つの速いといいますが、こうして数字で見ると早さをますます実感します。

当時も今も勉強時間の確保は悩みの種です。子供が大きくなったから時間を確保しやすくなるかといえば逆で、一緒に遊んでくれと頻繁にせがまれ、時間の制約はより厳しくなりました。

また、一時期は子供から「パパ嫌い」といわれることもありました。妻曰く、私のいないところでは「パパ好き」とも言ってくれたそうなのですが、自分が愛している存在から冗談でも嫌いと言われるのはきついものがありました。

そんな様子を見た妻からの提案で家庭内タスクの分担見直しを行いました。また、やり方を変えることにも取り組みました。結果、子供からは「お父さん好き」といってもらえるようになりました。

私の例が何かしらのヒントになればと願い、私(夫)視点での取り組みをここに書き残します。

なお、根底にある考え方は以前と変わりないので、よろしければ以前の記事も参照ください。
幼い子供の育児と自分の勉強時間確保の両立 - ぱと隊長日誌

家庭内タスクの分担見直し

分担見直し前までは私も妻も家庭内タスクの一部をシェアし合っていました。例えば、食器洗い・テーブル拭き・子供の遊びの付き合い・おむつ替えなどは分担を決めず、手の空いている方がやることにしていました。

これを見直し後は原則として妻が家事全般を行い、私は子供の面倒を見る、というタスク分担に切り替えました。これにはいくつか理由があります。

(1) 妻の家事を片付ける速度が速い

妻は家事を全て片付けてから寝たい性分です。また、家事を片付けるスピードは妻のほうが早いです。私が片づけを担当して時間をかけてしまうと、家族全員の寝るタイミングが遅くなってしまいます。

(2) 妻は子供と過ごす時間がもともと長い

妻は以下の理由から子供と過ごす時間が必然的に長くなります。

  • 時短勤務
  • 保育園の送迎
  • 寝かしつけ

こうした背景を踏まえると、妻が子供と遊ぶ時間を多少減らしたところで問題ないという判断になりました。

(3) 私が子供と過ごせる時間を延ばせる

私は残業を比較的抑えた勤務にしていますが、それでも家に帰ってから使える時間は限られています。その短い時間を少しでも子供の為に費やしたかったのです。

子供との遊び方の見直し

以前は子供と遊ぶときに全力で集中しなければとの思いがありました。

ですが、私は単調な遊びが苦手で、幼い子供の遊びはたいてい単調です。これが苦痛で仕方ありませんでした。

そこで、パーフェクトを目指さず、少し崩すことにしました。遊びながら自分の楽しみを入れることにしたのです。例えばこんなことです。

  • 横目でテレビを見る
  • 好きな音楽を流す
  • 合間にスマホいじり

以前であれば、遊びの最中のスマホいじりはありえないと考えていましたが、無理なく継続させるためにやむを得ないと考え直しました。それでも、話しかけられている最中は手を止めて向き合うなど、線引きを忘れないようにしています。

勉強時間の確保

これに関して以前の記事と大きな違いはありません。
幼い子供の育児と自分の勉強時間確保の両立 - ぱと隊長日誌

変わったのはますます早めの電車に乗るようにしたことです。これで座れる可能性が高まりました。そして、業務に余裕がある時期であれば、始業前の時間を勉強に充てました。

COVID-19 を機にリモートワークが進んだこともあり、通勤時間は削減されました。その分は勉強時間が増えるかと言えばそうとも言えず、私の場合は減ってしまいました。家にいると家族と過ごす時間が増え、家事や子供の相手に費やされるためです。ですが、妻の負担が減り、子供が楽しそうにしているを見ると、トレードオフとしては悪くなかったと感じています。

子どもが YouTube を見るようになり、その間は勉強時間に割くこともできます。ですが、YouTube の子守に甘えないよう心がけています。YouTube は勉強時間を作るためのツールというより、親が二人とも家事をしているときに子供の相手をしてもらうツール、と考えています。

まとめ

子育ては長期戦です。自分も家族も消耗せず、継続できることを心がけましょう。

勉強時間の確保は引き続き難しい課題です。でも、諦めることなく、細切れ時間を有効活用しましょう。ここでの積み重ねが将来活きてくるはずです。

キャリアも子育ても未来への投資と心がけましょう。

家族以上に犠牲を捧げる価値のあるものは、おそらくないのだろう。家族があなたのために自分を犠牲にするだけでなく、あなたも家族のために犠牲を払わなくてはならない。これこそが、深い友情や、充実した幸せな家庭生活、結婚生活の大切な土台だと、わたしは信じている。
イノベーション・オブ・ライフ ハーバード・ビジネススクールを巣立つ君たちへ
~第6講 そのミルクシェイクは何のために雇ったのか~

Oracle Cloud Infrastructure (OCI) 無償トレーニングのおすすめポイント

Oracle は「Oracle Cloud Infrastructure (OCI)」の無償トレーニングを継続して提供すると発表しました。
オラクル、Oracle Cloud Infrastructureのトレーニングと認定試験を無償で提供

OCI無償トレーニングと認定資格のページはこちらです。
OCI無償トレーニングと認定資格

実際に無償トレーニングを受講したところ、とても有用なトレーニングでした。実感したこと・分かったことをまとめます。

(1) 無償だけどボリュームはたっぷり

Learning Path のうち、「Japanese: Become OCI Architect (Associate): 日本語」を例に挙げます。ここでは『Oracle Cloud Infrastructure Architect Associate認定試験で扱われるトピックについて学習します』となっています。この Learning Path だけで27時間超のボリュームです。これだけの講義を無償で受講可能です。

Learning Path にはスキルチェックや Oracle Cloud Free Tier (こちらも無償)を使った Hands-On も含まれています。

(2) 1コマが短い

講義のボリュームは多いですが、1コマの時間は短く(大半が10分以内)設定されています。隙間時間を活用して進めることができます。

(3) Transcript がある

講義の書き起こし(英語)が用意されています。画面右側に表示された Sidebar から Transcript を選択します。

Transcript には以下の機能があります。

  • 動画と対応して自動的に進行する
  • テキストをクリックすると対応する場面までスキップする

(4) 各国語での字幕が用意されている

画面右下のアイコンから英語・日本語などの字幕表示が可能です。
OCIトレーニングの字幕表示設定
講義の大半は英語ですが、字幕表示を活用することで理解しやすくなります。

(5) インストラクターへ質問できる

画面左下の "Ask the Instructor" からインストラクターへ質問できます。
OCIトレーニングの質問方法
おそらくは英語のみ対応です。質問したところ、翌営業日には返信がありました。

これまで、他のサービスで提供された無償トレーニングも受講しましたが、今回のトレーニングは群を抜くサービスレベルでの提供だと感じました。資料や講義が英語だからと敬遠せず、字幕や書き起こしをうまく使いながら活用してはいかがでしょうか。