LoginSignup
2
3

【Python】sorted関数を利用して同じ組み合わせのクエリ実行(DBアクセス)を減らす方法

Posted at

概要

sorted関数を利用することで、 DBアクセスする回数を減らすことができましたので紹介します。

サンプルコード1

sorted関数とは、イテラブル(リスト、タプル、辞書など)をソートした新しいリストを返す関数。
以下、シンプルなサンプルコードです。

def sort_and_tuple(input_list):
    sorted_tuple = tuple(sorted(input_list))
    return sorted_tuple

my_list = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
result = sort_and_tuple(my_list)
print(result)  # (1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9)

sort_and_tuple関数は、入力としてリストを受け取り、そのリストをソートした後、タプルに変換して返します。このように、sorted関数とtuple関数を組み合わせることで、リストの要素をソートし、その結果を変更不可能なタプルとして保存することができます。

公式ドキュメントはこちら。

サンプルコード2

次に、fruit_list1fruit_list2という、異なる順序で同じ要素を持つリストで利用したコードです。
以下の通り、それぞれ別の順番ですが、ソートされたことで、これらのリストは関数内で「辞書のキー」として同じとみなされています。

def add_to_dict(input_list, value, my_dict):
    sorted_tuple = tuple(sorted(input_list))
    my_dict[sorted_tuple] = value

my_dict = {}

fruit_list1 = ['apple', 'banana', 'cherry']
value1 = "Fruit Salad"

fruit_list2 = ['cherry', 'banana', 'apple']
value2 = "Smoothie"

add_to_dict(fruit_list1, value1, my_dict)
add_to_dict(fruit_list2, value2, my_dict)
print(my_dict)  # {('apple', 'banana', 'cherry'): 'Smoothie'}

最後に追加された値がSmoothieなので、Smoothieだけが保持されていることがわかりますね。
異なる順序で同じ要素を持つリストが同じキーとして扱われたことが確認できました。

サンプルコード3

もう一つレベルアップして、冒頭で紹介した、DBアクセスを減らせる方法を紹介します。

もしも、順番が異なるだけの同じ組み合わせのクエリを(forループとかで)大量にDBアクセスしている場合、少しパフォーマンスに影響が出てしまいますよね。その場合、以下のように、sortedでまずはソートし、一度同じ組み合わせで取得したものは辞書に保存(キャッシュ)してあげる形にします。

class DataFetcher:
    def __init__(self):
        self.data_cache = {}

    def get_data(self, list1, list2, list3):
        key = (tuple(sorted(list1)), tuple(sorted(list2)), tuple(sorted(list3)))

        # キーが辞書に存在しない場合は、データを取得する
        if key not in self.data_cache:
            self.data_cache[key] = SampleModel.objects.filter(
                Q(field1__in=list1) & Q(field2__in=list2) & Q(field3__in=list3)
            ).distinct()

        return self.data_cache[key]

この例では、get_dataメソッド内でSampleModelからデータを取得し、それをキャッシュに保存します。実際にこのようにすることで、同じ組み合わせのクエリ実行が大幅に減りました。

ちなみに、Qオブジェクトは、複数のフィールドに対する複雑なクエリを作成するためのもの。

上記では、
field1list1のいずれかの値を持ち、
field2list2のいずれかの値を持ち、
field3list3のいずれかの値を持つ、
すべてのSampleModelオブジェクトを取得するコードになっています。

sortedメソッドもある

ちなみに、sorted関数とは別でsortedメソッドがあります。

numbers = [5, 2, 3, 1, 4]
numbers.sort()
print(numbers)  # [1, 2, 3, 4, 5]

これはリスト自体をソートするリストオブジェクトのメソッド。
こちらの場合は、新しいリストを返さず、元のリストを直接変更します。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3