2012-11-15 9 views
10

私は、クエリAndroidのSQLiteの性能

この

Cursor cursor = database.rawQuery(sql, args); 

cursor.moveToFirst(); 
while (!cursor.isAfterLast()) { 
    TeamStats stat = new TeamStats(); 

    stat.setTeamId(cursor.getLong(0)); 
    stat.setTeamName(cursor.getString(1)); 
    stat.setGamesPlayed(cursor.getInt(2)); 
    stat.setWins(cursor.getInt(3)); 
    stat.setTies(cursor.getInt(4)); 
    stat.setLoses(cursor.getInt(5)); 
    stat.setGoalsOwn(cursor.getInt(6)); 
    stat.setGoalsAgaist(cursor.getInt(7)); 
    stat.setScore(cursor.getInt(8)); 
    stat.setPoints(cursor.getInt(9)); 

    stats.add(stat); 
    cursor.moveToNext(); 
} 
cursor.close(); 

のように使用されているので、それは多くのテーブルから値を選択し

String sql = "SELECT s.team_id, s.team_name, s.gp, s.w, s.t, s.l, s.go, s.ga, s.score, s.p FROM " 
      + "(SELECT team_id, team_name, SUM (gp) gp, SUM (w) w, SUM (t) t, SUM (l) l, SUM (GO) go, SUM (GA) ga, SUM (GO)- SUM (GA) score, SUM (2*w+t) p FROM " 
      + "(SELECT t._id team_id, t.name team_name, COUNT(CASE WHEN score_home IS NOT NULL THEN 1 END) gp, COUNT (CASE WHEN score_home > score_away THEN 1 END) w," 
      + " COUNT (CASE WHEN score_home = score_away THEN 1 END) t, COUNT (CASE WHEN score_home < score_away THEN 1 END) l," 
      + " SUM (score_home) go, SUM (score_away) ga" 
      + " FROM team_table t LEFT OUTER JOIN match_table m ON m.team_home = t._id" 
      + " WHERE t.tournament_id = ? GROUP BY t._id, t.name" 
      + " UNION ALL" 
      + " SELECT t._id team_id, t.name team_name, COUNT(CASE WHEN score_away IS NOT NULL THEN 1 END) gp, COUNT (CASE WHEN score_home < score_away THEN 1 END) w," 
      + " COUNT (CASE WHEN score_home = score_away THEN 1 END) t, COUNT (CASE WHEN score_home > score_away THEN 1 END) l," 
      + " SUM (score_away) go, SUM (score_home) ga" 
      + " FROM team_table t LEFT OUTER JOIN match_table m ON m.team_away = t._id" 
      + " WHERE t.tournament_id = ? GROUP BY t._id, t.name)" 
      + " GROUP BY team_id, team_name) s" 
      + " ORDER BY s.p DESC, s.score DESC, s.go ASC"; 

のこの種を持っているとし、いくつかの操作を行いますなどとして、クエリがひどく複雑(非常にデバッグが難しい)であり、パフォーマンスが期待したほど良くないように見えます。私の質問は次の通りです:

  1. 何らかの準備文を使ってパフォーマンスを改善することはできますか?
  2. さらに簡単なクエリを実行して、カスタムコードで手動で処理する方が速いでしょうか?
+6

データベーススキーマを改善し、正規化を解除し、インデックスを追加してクエリがより簡単かつ高速になるようにします。 ['EXPLAIN QUERY PLAN'](http://www.sqlite.org/eqp.html)は、クエリでsqliteが何をするかを確認する良い方法です。 – zapl

+1

まず、何らかの形でクエリをフォーマットすることを検討する必要があります。 stackoverflowは、難読化されたSQL文を作成できることを示す場所であってはなりません。 – tkr

+1

@tkrまあ...まず、あなたの変更を拒否するためのdownvotingは、不自由です。次に、 'String sql'部分は必須です。これは、次のコードで使用されるためです。それが私があなたの変更を拒否した主な理由でした。周囲のコードをすべて削除して、私がそれを受け入れることを期待することはできません。次回は、あなたの行動について考え、自分自身を行動してください。 – user219882

答えて

6

もし私があなただったら、あなたのsqliteデータベースをホストにコピーし、バインドされた変数(?)をあなたが持っている実際の変数値に置き換えて、いくつかのSQLite GUIで手動で実行しようとします。 Windows上のGUIでは、私はSQLite Expert Personalが好きで、Linuxのsqlitemanはかなり良いです。

SQL(コマンドラインまたはGUI)をデバッグする際には、EXPLAINおよび/またはEXPLAIN QUERY PLANのSQL文を実行して解析してください。テーブルスキャンに注意してください。索引を追加して高価なスキャンを排除しようとする必要があります。しかし、すべてを索引付けしないでください。状況が悪化する可能性があります。 複合(複数列)インデックスを使用すると、パフォーマンスが大幅に向上することがよくあります。注意してください。任意のテーブルでは、SQLiteは(特定のSQL文を実行している間に)複数のインデックスを使用することはできませんので、インデックスを適切に選択してください。

(。またQuery Planningにおける基本的な説明を参照)、SQLiteの対Javaでのデータ処理に関するあなたの懸念に対処するために - 私は完全に最適化されたと思います(適切なインデックスで、など)SQLiteのクエリをリレーショナルデータに対してます(ほぼ)Javaでこのデータを手動で処理するよりも高速になるでしょう。これは、特にあなたのケースで真実でなければなりません。すべてのデータは基本的にリレーショナルです。

あなたのAndroid APKがJavaを使用すると、デフォルトでSQLiteよりも多くのメモリにアクセスする可能性があります。setMaxSqlCacheSize()PRAGMA cache_sizeに相当)を使用してデータベースのSQLiteキャッシュサイズを増やすことができます。 Androidのデフォルトは10(最大100)ですが、それを増やしてみて、あなたのクエリに違いがあるかどうかを確認してください。あなたはプリペアドステートメントを使用している場合 1.準備されたステートメントがはるかに 2. SQLインジェクションが 3困難であることがより安全であるため、それはあなたのために有益である2000年

0

高速クエリについての正確な回答ではありませんが、追加のヘルパーテーブルを使用して、実際のデータテーブルでトリガを定義してみてください。このようにすれば、集計されたデータの大部分をすぐに手に入れることができ、クエリがより簡単になります。

1

個人的には、Android上でクエリとデータベース構造をできるだけシンプルに保ち、コードを使って大規模な処理を行うことをお勧めします。

複雑なデータベース構造と、データの損失なしにさまざまなバージョンのアプリケーションのアップグレードやダウングレードを処理する必要があるため、1つの理由はすぐに手を抜けることがあります。私は現在、ある種のNoSQLの方法でデータを設定して処理する傾向があります。

もう1つの理由は、SQLiteには実世界のタスクで必要とされる多くの機能がなく、とにかくコードを通じてデータを処理することになるからです。 )

private String getRelitiveDistanceQuery(double lng, double lat, int max){ 
    return "SELECT *, " + 
    // NOTE: this long query was done because there are no trig functions in SQLite so this is an series expansion of some of the functions 
    "((3.14159265358979/2-(((("+Double.toString(lat)+"*0.0174532925199433)-("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/6+("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/120-("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/5040)*((`lat`*0.0174532925199433)-(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/6+(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/120-(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/5040)+(1-("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/2+("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/24-("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/720)*(1-(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/2+(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/24-(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/720)*(1-(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)/2+(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)/24-(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)/720))+1/6*((("+Double.toString(lat)+"*0.0174532925199433)-("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/6+("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/120-("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/5040)*((`lat`*0.0174532925199433)-(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/6+(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/120-(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/5040)+(1-("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/2+("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/24-("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/720)*(1-(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/2+(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/24-(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/720)*(1-(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)/2+(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)/24-(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)/720))*((("+Double.toString(lat)+"*0.0174532925199433)-("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/6+("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/120-("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/5040)*((`lat`*0.0174532925199433)-(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/6+(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/120-(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/5040)+(1-("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/2+("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/24-("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/720)*(1-(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/2+(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/24-(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/720)*(1-(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)/2+(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)/24-(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)/720))*((("+Double.toString(lat)+"*0.0174532925199433)-("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/6+("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/120-("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/5040)*((`lat`*0.0174532925199433)-(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/6+(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/120-(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/5040)+(1-("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/2+("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/24-("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)*("+Double.toString(lat)+"*0.0174532925199433)/720)*(1-(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/2+(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/24-(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)*(`lat`*0.0174532925199433)/720)*(1-(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)/2+(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)/24-(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)*(("+Double.toString(lng)+" -`lng`)*0.0174532925199433)/720))))) AS relDistance " + 
    "FROM `"+TABLE_ITEMS+"` ORDER BY relDistance ASC LIMIT "+Integer.toString(max); 
} 
私はこのコードを生成するためのperlスクリプトを書いた

、それは三角関数を展開していない、それは実際にはかなりうまく動作しますが、それは、例えば、そこにそう最も近い項目を見つけ、複雑しまった可能一切三角関数があります管理不能で、私はそれをお勧めしません。

2

まず、私はSQLiteについて詳しくは分かりませんが、MS SQL Serverのように動作すると思います。

このような単純な問合せのパフォーマンスの問題は、通常、部分的な表スキャンまたは表のシークではなく、完全な表スキャンの結果として失われる索引の場合に関係します。 team_table.tournament_idにインデックスがない場合、SQLiteはテーブル全体をスキャンして "t.tournament_id =?"を実行する必要があります。操作。 match_table.team_homeとmatch_table.team_awayでも同じことが起こります。欠落しているインデックスは、m.team_homeとm.team_awayの結合操作の完全なテーブルスキャンの結果になります。

残りについては、2つの方法でクエリを簡素化できます。最初は、外部サブクエリを削除し、Orderで順序付けした式または列を使用します。つまり、 "ORDER BY sp DESC、s.score DESC、s.go ASC"を "ORDER BY SUM(2 * w + t)DESC、SUM(GO) - SUM(GA)DESC、SUM GO)ASC "を実行し、サブクエリを取り除きます。

左を実行することにより、単一のクエリでUNIONを置き換えることであろう第二の方法は、同時にm.team_homeとm.team_awayの両方に結合操作:

... team_table FROM LEFT OUTER tを登録しようmatch_table m ON(m.team_home = t._idまたはm.team_away = t._id)...

その後、t._idがm.team_homeまたはm.team_awayに等しい場合のさまざまなスコアを適切に計算するために、Caseステートメントを変更するのは非常に簡単です。この方法では、UNIONを削除できるだけでなく、2番目のサブクエリを削除することもできます。

最後に、左結合の使い方を見てください。通常のInner Joinの使用よりも本当に必要かどうかはわかりません。

その後、Group ByとOrder By、サブクエリまたは共用体を持たず、おそらく左結合がない単純な結合クエリで終わるはずです。しかし、この時点で、Order Byの式は少し複雑になっているので、サブクエリを元に戻したり、列の順序を使用したり(最後にお気に入りの選択)するかのどちらかの判断を下す必要があります。

連合がなければ、クエリは少なくとも2倍の速さで実行する必要がありますが、最終的にはパフォーマンスが優れている必要があります。究極の要件はすべての適切なインデックスを持つことです。そうしないと、SQL Serverが複数の全表スキャンを実行する必要がある場合、パフォーマンスは良くなりません。

0

を - この設定のためにそのデスクトップのSQLiteデフォルトははるかに高いです注意してください。彼らはそれほど複雑ではありません 4.メンテナンスは簡単です

+0

私はそのすべてを知っていますが、アンドゥに_PreparedStatement_ものがあるかどうか疑問に思っていました。 – user219882

関連する問題