プログラミング方法を自分で教えようと、今までに注文したことのあるすべての書籍を表示するために小さなWebアプリケーション(Flask、SQLAlchemy、Jijna)を作成していますAmazonから。多対多の関係でクエリの速度を向上させよう
"barest bones"の可能な方法で、私はhttp://pinboard.inを複製する方法を学ぼうとしています。これは私のパラゴンです。 MaciejCegłowskiはまっすぐなGです...私は彼のサイトがどんなに速く走っているのか分かりません。私は160のブックマークエントリを読み込むことができます。すべてが関連タグ -in、dunno、500 ms? ...これは、私が下で議論されるように、ひどく間違って何かをやっているのを知っている理由です。
いずれにしても、books
クラスと私のtag
クラスの間に多対多の関係を作成しました。これは、ユーザーが(1) book
をクリックし、tags
を参照してください。また、(2)tag
をクリックし、関連するすべての書籍を参照してください。ここに私のテーブルのアーキテクチャは次のとおりです。
ここでは、2つのクラス間の関係のためのコードは次のとおりです。
assoc = db.Table('assoc',
db.Column('book_id', db.Integer, db.ForeignKey('books.book_id')),
db.Column('tag_id', db.Integer, db.ForeignKey('tags.tag_id'))
)
class Book(db.Model):
__tablename__ = 'books'
book_id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(120), unique=True)
auth = db.Column(db.String(120), unique=True)
comment = db.Column(db.String(120), unique=True)
date_read = db.Column(db.DateTime)
era = db.Column(db.String(36))
url = db.Column(db.String(120))
notable = db.Column(db.String(1))
tagged = db.relationship('Tag', secondary=assoc, backref=db.backref('thebooks',lazy='dynamic'))
def __init__(self, title, auth, comment, date_read, url, notable):
self.title = title
self.auth = auth
self.comment = comment
self.date_read = date_read
self.era = era
self.url = url
self.notable = notable
class Tag(db.Model):
__tablename__ = 'tags'
tag_id = db.Column(db.Integer, primary_key=True)
tag_name = db.Column(db.String(120))
問題
私はbooks
テーブルを反復処理した場合のみ(〜 400行)、照会が実行され、ブラウザーに落雷のスピードでレンダリングされます。問題はない。
{% for i in book_query %}
<li>
{{i.notable}}{{i.notable}}
<a href="{{i.url}}">{{i.title}}</a>, {{i.auth}}
<a href="/era/{{i.era}}">{{i.era}}</a> {{i.date_read}}
{% if i.comment %}
<p>{{i.comment}}</p>
{% else %}
<!-- print nothing -->
{% endif %}
</li>
{% endfor %}
しかし、私は次のように私はfor loop
を入れ子にすることで、コードを変更する、ブックに関連付けられている任意およびすべてのタグを表示したい、場合:
{% for i in book_query %}
<li>
{{i.notable}}{{i.notable}}
<a href="{{i.url}}">{{i.title}}</a>, {{i.auth}}
<a href="/era/{{i.era}}">{{i.era}}</a>
{% for ii in i.tagged %}
<a href="/tag/{{ii.tag_name}}">{{ii.tag_name}}</a>
{% endfor %}
{{i.date_read}}
{% if i.comment %}
<p>{{i.comment}}</p>
{% else %}
<!-- print nothing -->
{% endif %}
</li>
{% endfor %}
クエリが遅く大幅(約20秒かかります)。私の理解では、book
テーブルのすべての行に対して、のassoc
テーブル全体(つまり、「フルテーブルスキャン」)を繰り返すため、これが起こっていると私は理解しています。
議論(または、「私が考えることは起こっている」)明らかに
、私は完全にnoobのは - 私は〜3ヶ月間のプログラミングされています。物事を動かすことを動機づけていますが、知識ベースに大きなギャップがあることはわかります。右そのバットオフ
、私はそれがそれぞれの新しい本で、コードが全体関連付けテーブルを反復されることを非常に非効率的だということを理解することができる(つまり、私はそれがあると信じている、何が起こっているのか、実際の場合)。 assoc
テーブルをクラスタ化(?)またはソート(?)する必要があると思います.テーブル内のbook_id == 1
の行を再度チェックすることはありません。言い換えれば
は、私が起こっていると思いますが、この(computerspeakで)です:
- ああ、彼は
books
テーブル内book_id == 1
と本が - オーケータグ付けされているか知りたい、私を聞かせて
assoc
テーブル - ロー#1 ...
assoc
テーブルのbook_id
は1
に等しいですか? - さて、そうです。 Row#1には
tag_id
は何ですか? ... [コンピュータはtag
テーブルにアクセスしてtag_name
を取得し、ブラウザに返します] - 行#2 ...
book_id
はassoc
のテーブルは1
に等しいですか? - いいえ、いいえ、行番号3に行きます。
- 私のプログラマーは愚かで、この表を何らかの方法で並べ替えたり索引付けしなかったので、私は我々は
books table
にbook_id == 2
に得れば、コンピュータが本当に怒る、その後
...おそらくこれ以上がないときbook_id == 1
を探して全体assoc
テーブルを通過する必要があります:
- さて、彼は一緒に行くすべてのタグを知りたい
book_id == 2
- さて、私はすでにこれをチェックしませんでした...私は...
assoc
テーブル - 行#1に行く秒を待ってみましょう?聖なること#t、私はこれを何度も繰り返さなければならないのですか?
- 大丈夫...いいえ...行番号1 ...は
book_id == 2
ですか?
質問
を(...私はそれがない知っている!しかし、私は私のプログラマはDUM-DUMあるので、とにかくチェックしなければならない)そこで問題は、私は(1)ソート(することができますか? )またはクラスタ(?)のassoc
テーブルをassoc
テーブルを介してより知的なトラバーサルを保証する何らかの方法で、または私の友人が示唆したようにI(2)は「良いSQLクエリを書くことを学ぶ」ですか? (注、私は気錬金術... SQLAlchemyのですべてを扱うしてきたので、私は秘密やその他もろもろでその魔法をenshrouding ... SQLを学んだことがありません。)
最後の言葉任意の入力のための
感謝。私がstackoverflowで質問する方法を改善する助けとなる提案があれば(これは私の最初の投稿です!)私に教えてください。