5028 words
25 min

PySparkとは? PythonやSQLと何が違うのか実際に比較してみた

PySparkという名前は前から耳にしていたが、ぶっちゃけ最初は何者なのかよく分かっていなかった。

「PySpark」っていうくらいだし、Pythonを使って何かやるライブラリなのだろうとは思っていたが、

普通のPythonと何が違うんだろう?

という部分がイマイチピンときていなかった。

さらに調べていると、Spark SQLなんて言葉も登場。

SQLで集計できるなら、わざわざPySpark使わなくてもよくね?

という新たな疑問も浮上。

もう一つ気になったのが「大量データ処理」の文脈。
なぜデカいデータを扱うときにPySparkがもてはやされるのか。

「Pythonより単に速いからなのかな?」とも思ったが、考えててもラチがあかないので、今回はWindowsのローカル環境でPySparkを動かしてPythonやSQLite + SQLと比較してみることにした。

PySparkの基本的な仕組みを調べつつ、同じデータをPython・SQL・PySparkで回してみて、実行計画や処理時間も確認してみる。

この記事の対象読者#

  • PySparkという言葉を初めて聞いた人
  • PySparkと普通のPythonの違いがピンときていない人
  • SQLとPySparkの違いや使い分けが分からない人
  • Sparkが裏側で何をやっているのか知りたい人
  • ローカル環境でPySparkをちょっと試してみたい人

まず結論#

今回調べて、実際に動かしてみて分かったことを先にまとめておく。

結論1:PySparkは「Pythonを高速化したやつ」ではない#

PySparkは、Apache SparkのPython API

つまり、Pythonそのものを爆速にするライブラリというより、PythonからSparkのデータ処理エンジンを操作するための入口と考えた方がしっくりくる。PySparkは公式でも「Python API for Apache Spark」と説明されていて、PyPIからサクッとインストールしてローカルで試すこともできる。

結論2:Spark SQLとPySparkは単純な別物ではない#

PySparkからSpark SQLを普通に実行できる。

しかもSpark内部では、SQLで書こうがDataFrame APIで書こうが、最終的な計算にはまったく同じ実行エンジンが使われる仕組みになっている。

なので、

「SQLかPySparkか、どちらか一方を選ぶ」

みたいな単純な二者択一の関係ではないっぽい。

結論3:PySparkだからといって必ずPythonより速いわけではない#

今回1,000万行のデータで検証してみたところ、読み込み後の集計処理だけを見れば local[5] のPySparkが一番速かった。

ただ、Sparkの起動時間やCSV読み込みまで含めたトータル実行時間だと、今回のローカル環境ではまさかのPython単体の方が速いという結果に。

つまり、

「PySparkを使えばPythonより絶対に速くなる」

とは一概には言えない。

「PySparkってPythonと何が違うの?」という素朴な疑問に対しては、速度というより処理を実行する仕組みそのものが根本的に違うと捉えるのが一番しっくりきた。


そもそもPySparkとは何者?#

基本的な定義#

PySparkは、Apache SparkをPythonから操作するためのAPI。

Apache Spark自体は、大規模なデータを扱うための分散処理基盤。PySparkを使うことで、PythonからSparkのDataFrameやSQL機能を扱えるようになる。

イメージ的にはこんな感じ。

Python

PySpark

Apache Spark

データ処理

ここが最初に少し混乱したポイントだった。

「PySpark」という名前から、最初は「Python製の高速データ処理ライブラリ」みたいなイメージを持っていたが、実際はPythonからSparkという別物を動かすための窓口と考える方がしっくりくる。


Sparkの内部はどうなってるの?#

ここで「じゃあそもそもSparkって中で何やってるの?」という話。

Sparkアプリケーションは、主に DriverExecutor というプロセス群で動いている。

公式ドキュメントによると、Driverが SparkContext を保持して全体を指揮し、Executorが実際にタスクを実行してデータをメモリ上に保持する構成になっている。Driverから各ExecutorへTaskが配られるイメージ。

構成を図にするとこんな感じ。

flowchart TB
    App["Sparkアプリケーション"]
    Driver["Driver (SparkContext)"]

    Executor1["Executor 1"]
    Executor2["Executor 2"]

    Task1["Task 1"]
    Task2["Task 2"]

    Data1["Data 1"]
    Data2["Data 2"]

    App --> Driver

    Driver --> Executor1
    Driver --> Executor2

    Executor1 --> Task1
    Executor2 --> Task2

    Task1 --> Data1
    Task2 --> Data2

今回の検証は1台のWindows PC上でSparkを動かしている。
なので本格的な複数台マシンによる分散処理ではない。
とはいえ、Sparkの分散処理モデルの雰囲気をローカルで体感することは十分可能。


local[1]local[5] って何?#

Sparkをローカル環境で動かすとき、以下のような指定ができる。

local[1]
local[5]
local[*]

Spark公式での意味は以下の通り。

  • local[1] → 1つのワーカースレッドで動かす
  • local[K] → K個のワーカースレッドで動かす
  • local[*] → マシンの論理コア数いっぱいで動かす

今回の検証PCは20論理プロセッサ搭載だが、CPU負荷を考慮して local[1]local[5] の2パターンで試してみた(local[*] は今回は見送り)。


なぜにSparkの概念が必要になるのか?#

ここが一番気になった部分。

単にデータを集計するだけなら、

CSV

Python

集計

で済むし、SQLを使うにしても、

CSV

SQLite

SQL

集計

で十分なはず。

じゃあ、なんでわざわざSparkなんて大掛かりなものが必要になるのか?

Spark公式のクラスタ概要を見ると、DriverがTaskを分散し、複数のExecutorで並列処理する前提で作られている。つまり最初から「1つのPythonプロセスで全データを順番に処理する」という世界観ではない。

なのでSparkの本当の価値は、

Pythonコードを単に高速化すること

というより、

超巨大なデータを複数のブロックに分解して並列実行できる仕組み

にあると考える方が自然っぽい。

ただし、このあたりの恩恵は1台のPCのローカル検証だけだと全貌は見えにくいかもしれない。


PySparkのDataFrameって普通のリストやPandasと違うの?#

PySparkでは、データをDataFrameという単位で扱う。

コードの書き方自体はこんな感じ。

result = (
    df.withColumn(
        "total_sales",
        col("price") * col("quantity")
    )
    .groupBy("category")
    .agg(
        spark_sum("total_sales").alias("total_sales")
    )
    .orderBy("category")
)

一見すると、普通のPythonオブジェクトをメソッドチェーンで操作しているように見える。

が、PySparkのDataFrameはPythonの普通のリストやDictとは別物。

Spark公式によると、DataFrameは構造化されたデータの「分散コレクション」として定義されている。さらにSpark SQLの最適化エンジン(Catalyst Optimizerなど)が働くことで、計算手順が最適化されてから実行される。

Pythonの for row in rows: みたいに1行ずつ真面目に処理していくのとは、根本的に仕組みが違う。


実際にPython・SQL・PySparkを比較してみた#

というわけで、ここから実際に動かして比較してみる。

検証環境#

項目内容
OSWindows 11
CPUIntel Core Ultra 7 265K
論理プロセッサ20
メモリ約63.35GB
Python3.13.15
JavaTemurin 21.0.12.1
PySpark4.2.0
Spark4.2.0
Spark実行方式local[1] / local[5]
SQLSQLite

※PySpark 4.2.0公式では Python 3.10+、Java 17+ が要件。今回は Python 3.13.15 と Java 21 を使用。


今回使用したデータ#

検証用に、以下のようなシンプルな売上データ(CSV)を用意した。

id,product,category,price,quantity
1,Apple,A,100,3
2,Banana,B,200,2
3,Orange,A,150,4
4,Grape,C,300,1
5,Melon,B,500,2
...

ここから、

売上金額 = price × quantity

を計算し、category ごとに合計売上金額を集計する。

たとえば10行のダミーデータなら、期待する結果は以下。

categorytotal_sales
A1700
B2600
C1770

検証1:Python単体で集計する#

まずは一番素直なPython標準ライブラリでの処理。

with CSV_FILE.open(newline="", encoding="utf-8") as f:
    reader = csv.DictReader(f)

    for row in reader:
        category = row["category"]
        price = int(row["price"])
        quantity = int(row["quantity"])

        totals[category] += price * quantity

PythonがCSVを開き、1行ずつDictにしてループで集計していくスタイル。

CSV

Python

1行ずつル〜プ処理

集計

出力結果は当然こうなる。

A 1700
B 2600
C 1770

検証2:SQLite + SQLで集計する#

次はSQL。

Python組み込みの sqlite3 を使ってメモリ上(":memory:")にテーブルを作って集計してみた。

SQL文は標準的なやつ。

SELECT
    category,
    SUM(price * quantity) AS total_sales
FROM sales
GROUP BY category
ORDER BY category

結果は当然同じ。

A 1700
B 2600
C 1770

Pythonのループ処理と比べると、コードの書き味はかなり変わる。

Pythonでの書き方#

for row in reader:
    totals[category] += price * quantity

SQLでの書き方#

SELECT
    category,
    SUM(price * quantity)
FROM sales
GROUP BY category

最初は「SQLとPySparkってライバル関係なのかな?」と思ってたが、ここで少し視点が変わってきた。


検証3:PySpark(DataFrame API)で集計する#

PySparkでの書き方はこんな感じ。

result = (
    df.withColumn(
        "total_sales",
        col("price") * col("quantity")
    )
    .groupBy("category")
    .agg(
        spark_sum("total_sales").alias("total_sales")
    )
    .orderBy("category")
)

実行結果は勿論これ。

A 1700
B 2600
C 1770

結果自体は一緒だが、大事なのは「裏で何が起きているか」。

PythonはPythonのインタプリタが1行ずつ律儀に回しているが、PySparkの方は「こういう処理をしてね」というプランをSparkエンジン側に組み立ててから実行させている。


検証4:PySparkの中でSQLを使う#

ここで「SQLじゃだめなの?」という疑問を深掘りしてみる。

実はPySparkでは、DataFrameを一時ビュー(TempView)として登録できる。

df.createOrReplaceTempView("sales")

登録しちゃえば、普通にSQLが書ける。

result = spark.sql("""
    SELECT
        category,
        SUM(price * quantity) AS total_sales
    FROM sales
    GROUP BY category
    ORDER BY category
""")

つまり構造としてはこう。

PySpark
 ├─ DataFrame API (メソッドチェーンで書く)

 └─ Spark SQL (クエリ文字列で書く)

両方使える。

Spark公式ドキュメントでも「SQLとDataFrame APIは表現が違うだけで、裏側の計算エンジンは同一」と明言されている。

なので、

「SQLかPySparkか」

という比較ではなく、

「Sparkの上で、SQLとDataFrame APIのどっちの書き方で指示を出すか」

という話だったことが分かった。


検証5:実行計画を見てみる#

せっかくなので、Sparkの裏側(実行計画)を覗いてみる。

PySparkには explain() メソッドがある。

result.explain(mode="formatted")

Spark SQLで書いた場合の実行計画を出してみると、こんな感じのフローになっていた。

Scan csv

HashAggregate

Exchange

HashAggregate

Exchange

Sort

AdaptiveSparkPlan

DataFrame APIで書いた場合もほぼ同じ。

Scan csv

Project

HashAggregate

Exchange

HashAggregate

Exchange

Sort

AdaptiveSparkPlan

Scan csv って何?#

CSVファイルを読み取っているステップ。category price quantity といった必要な列をスキャンしている。

Project って何?#

DataFrame APIで指定した .withColumn("total_sales", col("price") * col("quantity")) の部分。
price * quantity の計算を行って total_sales という列を作るステップが Project として現れている。

SQL版だと SUM(price * quantity) の中に直接書いたため独立した Project ノードとしては見えなかったっぽい。

Exchange って何?(ちょっと気になったポイント)#

一番目についたのが Exchange

詳細を見ると hashpartitioning(category, 200) みたいな記述がある。
GROUP BY category を処理するために、データをカテゴリごとにパーティション再配置(シャッフル)しているということ。

元のデータ

categoryを基準にデータを再配置(Exchange)

集計(HashAggregate)

単にファイルを上から読んで加算しているわけではなく、分散処理に適した形でデータを並び替えてから集計しているのが見て取れる。


性能も比較してみた#

ここまでの仕組みを踏まえて、「で、実際に処理速度はどれくらい違うの?」を測ってみた。

※測定条件:

  • Windows 11 / 同一PC / 同一CSV / 同一集計処理
  • PySparkは local[1]local[5]

注意点として、PythonとPySparkではメモリ構造も動作原理も違うため、あくまで「今回の条件での測定値メモ」として見てほしい。


1,000万行のデカいCSVで勝負#

1,000万行のテスト用CSVを作成。
Python側はCSV読み込み完了後の「純粋な集計処理(5回測定)」のタイムを計測。

Python単体#

測定値(秒):

  • 0.392956
  • 0.389598
  • 0.380789
  • 0.408727
  • 0.390020

平均:0.392418秒 / 中央値:0.390020秒


PySpark local[1] (スレッド数: 1)#

ウォームアップ実行後、5回測定。

測定値(秒):

  • 0.602338
  • 0.589854
  • 0.591355
  • 0.588073
  • 0.573362

平均:0.588996秒 / 中央値:0.589854秒


PySpark local[5] (スレッド数: 5)#

測定値(秒):

  • 0.294400
  • 0.247066
  • 0.238032
  • 0.230247
  • 0.231689

平均:0.248287秒 / 中央値:0.238032秒


性能結果を並べてみる#

方法平均中央値
Python0.392418秒0.390020秒
PySpark local[1]0.588996秒0.589854秒
PySpark local[5]0.248287秒0.238032秒

中央値で比較すると、

PySpark local[5]  → 0.238秒 (最速)
Python            → 0.390秒
PySpark local[1]  → 0.590秒

マルチスレッドな local[5] にすると、Python単体より約1.64倍速くなった。
一方でシングルスレッドの local[1] だと、オーバーヘッドのせいかPython単体より遅いという結果に。

ここからも、

「PySparkにすれば無条件でPythonより速くなる」

わけではなく、並列度を効かせることで初めて集計処理が速くなるということが良くわかる。


実行時間全体(トータルタイム)でも比較してみた#

今度は「CSVの読み込み」や「Spark/JVMの起動コスト」も含めた全体の時間を測定してみた。

1,000万行データでの結果:

方法実行時間
Python7.065秒
PySpark local[1]12.823秒
PySpark local[5]8.443秒

まさかのPython単体が一番早いという結果に!

【集計処理だけ】
PySpark local[5] > Python

【起動や読み込みも含めた全体】
Python > PySpark local[5]

見事な逆転劇。

なぜこうなるかというと、PySparkは背景でJVM(Java仮想マシン)やSparkセッションを立ち上げる初期化コストがかかるため。

ローカルPCで中規模程度の処理を1回だけサクッと動かすようなケースだと、PySparkの初期化オーバーヘッドが響いてトータルではPython単体の方が早くなる、というオチ。

「PySpark=単なるPythonの高速化ツール」という認識がいかにズレているかが実感できる面白い結果となった。


local[1]local[5] の並列度の差#

データ量によって並列度の差がどう出るかも実験してみた。

10万行#

  • local[1]:約0.336秒
  • local[5]:約0.337秒
    → データが小さいと差はほぼゼロ。

100万行#

  • local[1]:約0.378秒
  • local[5]:約0.374秒
    → まだ明確な差は出ない。

1,000万行#

  • local[1]0.590秒
  • local[5]0.238秒
    → ここで一気に差が開く、、、!

データ量が小さいうちはオーバーヘッドの方が大きく、1,000万行クラスになって初めてマルチスレッド(local[5])の効果がはっきり現れるっぽい。


調べる前と後で考え方が変わった#

調べる前#

  • 「PySparkってPythonで大量データを爆速処理するライブラリでしょ?」
  • 「SQLで集計できるならPySparkなんて要らなくね?」

調べた後#

  • PySparkはPythonを直接速くする魔法ではなく、Sparkエンジンを動かすためのAPI。
  • 裏ではDriver / Executor / Task という分散実行モデルが動いている。
  • SQLかPySparkかの二者択一ではなく、Sparkの上で「SQL表記で書くかDataFrame表記で書くか」の違い。

イメージがガラッと変わった。


「Pythonじゃだめなの?」への回答#

ローカルPCで小〜中規模のデータをサクッと集計するだけなら、普通にPython単体で十分なケースが多い。

実際、今回の1,000万行の全体処理時間はPython単体の方が速かった。

ただ、データ量が単一マシンのメモリを超えたり、分散クラスタ環境で処理したい場合には、Python単体だと限界が来る。その時にSparkの分散実行モデルをPythonから使えるのがPySparkの強み。

「Pythonより必ず速いから使う」というより、「Sparkの分散実行モデルを使いたいから、書きやすいPythonからPySpark経由で触る」 というのが正しい捉え方っぽい。


「SQLじゃだめなの?」への回答#

SQLでも全然OK。今回SQLiteでも同じ集計ができた。

しかもSpark内部にもSpark SQLがある。

なので「SQLだと対応できないからPySparkを使う」というわけではない。

Spark
 ├─ Spark SQL(SQLで記述)
 └─ DataFrame API(Python等のコードで記述)

どっちで書いても裏の計算エンジンは同じなので、チームの好みや処理の複雑さ(前処理のループや条件分岐が多いならDataFrame API、単純集計ならSQLなど)で選べばOK。


注意点・今回分からなかったこと#

  1. 1台のローカルPCでの検証に過ぎない
    Spark本来の強みである複数台ノードでの分散環境では試していない。
  2. 動作環境依存
    Windows 11, Core Ultra 7 265K, メモリ64GBでの検証結果なので、環境が変われば数値も変わる。
  3. Windows環境での警告
    winutils.exenative-hadoop が無いという警告が出たが、今回のCSV処理自体は正常終了した。実運用環境では要確認。

まとめ#

  • PySparkはPythonを高速化するライブラリではなく、Apache SparkをPythonから操作するAPI
  • 裏では実行計画が組み立てられ、データが再配置(Exchange)されたりTaskに分割されて動く。
  • SQLとPySpark(DataFrame API)は競合ではなく、同じSparkエンジン上の表現違い。
  • ローカル環境&1,000万行程度だとトータル処理時間はPython単体の方が速いこともある。
  • 大量データや分散処理の仕組みが必要になって初めてPySpark(Spark)の真価が発揮される。

「PySpark=Pythonの高速版」と思って触ると「あれ、意外と遅くね?」と困惑するが、実行モデルや裏側の仕組みを理解すると使いどころが見えてくる、という話だった。


今後調べたいこと#

今回の検証で、逆に新しい疑問も出てきた。

特に気になったのが、

Partition
Task
Stage
Exchange
Shuffle
Driver
Executor

の関係。

今回 explain() を見ることで、Sparkが単純なPythonのループ処理ではないことは分かった。

ただ、

「実際にデータがどのように分割され、Taskとして処理されているのか?」

までは、まだ十分に理解できていない。

また、今回はローカルPCの local[1] / local[5] までしか試していないため、

複数ノードのSparkクラスタになると何が変わるのか?

も気になっている。

このあたりは、今回の記事とは分けて書かないとごちゃごちゃになっちゃいそうなので、別記事で。。。


参考資料#

今回使用したGithubコード群

ryo50
/
pyspark-blog-test
Waiting for api.github.com...
00K
0K
0K
Waiting...
  • Apache Spark 4.2.0 PySpark Installation
    PySparkのPython対応バージョン、PyPIからのインストール、Java要件など。

  • Apache Spark 4.2.0 Spark SQL, DataFrames and Datasets Guide
    Spark SQL、DataFrame API、同一実行エンジンについて。

  • Apache Spark 4.2.0 Cluster Mode Overview
    Driver、Executor、Task、Stageなどの構成について。

  • Apache Spark 4.2.0 Submitting Applications
    local[K]local[*]spark-submitなどについて。

  • PySpark 4.2.0 DataFrame.explain()
    実行計画の確認方法について。

  • Python 3.13 sqlite3 documentation
    SQLiteとPython標準のsqlite3について。

※今回の記事の検証結果は、2026年8月29日時点の環境で実施したもの。
PySparkやJava、Pythonのバージョン、Sparkの仕様は今後変更される可能性があるため、記事公開時には公式ドキュメントも再確認してね。

PySparkとは? PythonやSQLと何が違うのか実際に比較してみた
https://tech.storias-blog.com/blogs/py_spark/
作者
Storia
公開日
2026-08-29