관련 학습 권장사항:
python 비디오 튜토리얼TPC-C는 창고 네트워크를 시뮬레이션합니다. 동시에 실행되는 다양한 유형과 복잡성의 5개 트랜잭션의 조합으로 구성됩니다. 이 테스트의 목적은 여러 가상 사용자가 동시에 데이터베이스에 액세스할 때 트랜잭션 처리 속도를 평가하는 것입니다. 저는 이 작업에 적합한 TPC-C 테스트 방법을 사용하여 두 개의 Python ORM(SQLALchemy 및 PonyORM)을 테스트하기로 결정했습니다. 이 테스트의 목적은 여러 가상 사용자가 동시에 데이터베이스에 액세스할 때 트랜잭션 처리 속도를 평가하는 것입니다. 테스트 지침 첫 번째 단계는 창고 네트워크의 데이터베이스를 생성하고 채우는 것입니다. 데이터베이스에는 8개의 관계가 포함되어 있습니다: 1. 창고 2. 구역 3. 주문 4. 주문 라인 5. 재고 6. 프로젝트 7. 고객 8. 역사일반적으로 Tortoise 벤치마크는 다양한 ORM의 쿼리 실행 속도를 평가할 수 있습니다. 그러나 이 테스트 방법에는 결함이 있습니다. 대부분의 ORM은 웹 애플리케이션용으로 선택됩니다. 이 경우 여러 사용자가 데이터베이스에 모든 방식의 쿼리를 보내는 경우가 많습니다. 이러한 맥락에서 Python ORM의 성능을 평가할 수 있는 평가된 벤치마킹 도구가 없기 때문에 비교하기 위해 자체 PonyORM과 SQLAlchemy를 작성하기로 결정했습니다. 기본적으로 TPC-C 벤치마크를 사용했습니다. TPC는 1988년부터 데이터 처리 분야를 개발하고 테스트해 왔습니다. 거의 모든 장치 공급업체가 다양한 하드웨어 및 소프트웨어 샘플에서 이를 사용하면서 업계 표준이 된 지 오래되었습니다. 이러한 테스트의 주요 특징은 실제 조건에 최대한 가깝게 큰 부하에서 테스트하는 데 중점을 둔다는 것입니다.
Pony와 SQLAlchemy의 데이터베이스는 동일합니다. 기본 키와 외래 키만 인덱싱됩니다. Little A는 자동으로 이러한 인덱스를 생성합니다. SQLAlchemy에서는 수동으로 만들었습니다. 테스트 중에 여러 가상 사용자가 데이터베이스에 다양한 유형의 트랜잭션을 보냈습니다. 각 트랜잭션에는 여러 요청이 포함됩니다. 다양한 발생 확률로 처리를 위해 제출된 총 5가지 유형의 거래가 있습니다: 거래: 1. 신규 주문-45% 2. 결제-43% 3. 주문_상태-4% 4 . 배송 - 4% 5. 재고 수준 -4% 거래 발생 가능성은 기존 TPC-C 테스트와 동일합니다. 그러나 기술적 한계로 인해 다음 프로세서의 성능을 테스트하고 싶었기 때문에 원래 TPC-C 테스트는 64GB 이상의 RAM이 있는 서버에서 수행되었습니다(많은 프로세서와 거대한 디스크 공간) . 엄청난 부하를 견딜 수 있는 하드웨어의 능력보다는 ORM이 필요하므로 이 테스트는 다소 단순화되었습니다. TPC-C 테스트와의 주요 차이점은 다음과 같습니다. 주요 차이점: 1. 이 테스트는 원래 테스트보다 더 적은 수의 가상 사용자로 실행됩니다 2. 내 테스트에는 테이블 항목이 적습니다. 예: 원래 테스트에서 "재고" 관계의 항목 수는 100,000 * W 공식을 사용하여 계산되었습니다. 여기서 W는 창고 수입니다. 이 테스트에서는 100*W입니다. 3. TPC-C에서 일부 트랜잭션에는 데이터베이스에서 데이터를 쿼리하기 위한 여러 옵션이 있습니다. 예를 들어, 결제 거래에서는 ID로 데이터베이스에서 고객을 요청할 가능성이 있고 성과 이름으로 다른 고객을 요청할 수 있습니다. 현재 내 테스트에서는 ID로만 호출합니다. 4. 내 테스트 데이터베이스에는 TPC-C보다 테이블이 하나 적습니다. TPC-C 테스트에서는 주문이 생성된 후 Order 테이블과 NewOrder 테이블에 추가됩니다. 주문이 전달되면 NewOrder 테이블에서 삭제됩니다. 이렇게 하면 분당 많은 수의 트랜잭션을 적용할 때 작업 속도가 빨라질 수 있지만 데이터베이스에 액세스하는 사용자가 적으므로 이는 필요하지 않습니다. 대신 주문 테이블에 주문이 배송될 때까지 False가 되는 부울 속성 "is_o_delivered"를 추가했습니다. 다음으로 각 트랜잭션의 역할에 대해 간략하게 설명하겠습니다. 거래 수 새 명령 1. 두 가지 매개변수를 거래에 전달합니다: 창고 ID와 고객 ID 2. 전달된 ID를 사용하여 데이터베이스에서 창고와 고객을 선택합니다 3. 다음 중 하나를 무작위로 선택합니다. 데이터베이스 창고 영역 4. 주문 라인 수를 나타내는 난수를 생성합니다. 5. 주문 객체 생성
6. OrderLine 개체를 생성하는 루프입니다. 루프가 반복될 때마다 항목 테이블에서 무작위 항목을 선택합니다
7. 주문에서 각 항목의 재고를 변경합니다
Payment
1. 두 매개변수를 트랜잭션에 전달합니다: 창고 ID 및 고객 ID
2 . 전달된 ID로 데이터베이스에서 창고 및 고객 선택
3. 데이터베이스에서 창고 영역을 무작위로 선택
4. 결제 금액을 나타내는 임의의 숫자 생성
5. 창고 및 영역의 잔액을 결제 금액
6. 결제 금액만큼 고객 잔액이 감소합니다
7. 고객 결제 카운터가 증가합니다
8. 고객 결제 금액의 합이 증가합니다
9. 히스토리 객체 생성
주문 상태
1. 고객 ID를 거래 매개변수로 전달합니다.
2. ID와 고객의 마지막 주문으로 고객을 선택합니다.
3. 주문에서 주문 상태와 주문 라인을 가져옵니다.
Delivery
1. 창고 ID를 거래 매개변수로 전달
2. 데이터베이스에서 창고와 모든 지역을 선택합니다
3. 각 지역에서 가장 오래된 미배송 주문을 선택합니다.
4. 배송 상태를 True로 변경하는 각 주문의 경우
5. 주문 수량이 증가하는 각 고객의 경우
재고 수준
1. 창고 ID를 거래 매개변수로 전달
2. 데이터베이스 창고 선택
3. 창고에 있는 마지막 20개 주문 선택
4. 주문의 각 항목에 대해 해당 항목의 재고 수준을 평가합니다.
감지 결과
테스트에 참여하는 두 개의 ORM이 있습니다.
1. SQLAlchemy (그래프의 파란색 선)
2. PonyORM (그래프의 주황색 선)
다음은 2개의 병렬 프로세스를 통해 데이터베이스에 접근하여 10분간 테스트를 실행한 결과입니다. Multiprocessing 모듈을 사용하여 프로세스를 시작합니다.
5개의 거래가 테스트되었습니다. 이번 테스트 결과 리틀A의 속도는 기존보다 약 2배 정도 빨라진 것으로 나타났다.
평균 속도:
·소규모 A-2543 트랜잭션/분
·SQLAlchemy-1353.4 트랜잭션/분
이후에는 5개의 트랜잭션에서 ORM의 성능을 별도로 평가하기로 결정했습니다. 아래는 각 거래에 대한 결과입니다.
새 명령
평균 속도:
· 소규모 A-3349.2 거래/분
·SQLAlchemy -4110.6 거래/분 y-716.9 업무/분
· 소규모 A-323.5 거래/ 분
재고량
평균 속도 :
·소규모 A-677.3트랜잭션/분
·SQLAlchemy-167.9트랜잭션/분
테스트 결과 분석
결과를 받고 왜 그런지 분석해 보니 다음과 같은 결론이 나왔습니다.
5개의 트랜잭션 중 4개에서 PonyORM은 SQL 코드를 생성할 때 Python 표현식을 SQL 결과로 변환하는 것을 기억하기 때문에 더 빠릅니다. 따라서 Pony는 쿼리가 반복될 때 표현식을 다시 변환하지 않는 반면, SQLAlchemy는 쿼리를 실행해야 할 때마다 강제로 SQL 코드를 생성합니다.
Pony의 쿼리 예:
stocks = select(stock for stock in Stock if stock.warehouse == whouse and stock.item in items).order_by(Stock.id).for_update()
생성된 SQL:
SELECT “stock”.”id”, “stock”.”warehouse”, “stock”.”item”, “stock”.”quantity”, “stock”.”ytd”, “stock”.”order_cnt”, “stock”.”remote_cnt”, “stock”.”data”FROM “stock” “stock”WHERE “stock”.”warehouse” = %(p1)s AND “stock”.”item” IN (%(p2)s, %(p3)s)ORDER BY “stock”.”id”FOR UPDATE {‘p1’:7, ‘p2’:7, ‘p3’:37} SQLAlchemy: stocks = session.query(Stock).filter( Stock.warehouse == whouse, Stock.item.in_( items)).order_by(text(“id”)).with_for_update()
생성된 SQL:
SELECT stock.id AS stock_id, stock.warehouse_id AS stock_warehouse_id, stock.item_id AS stock_item_id, stock.quantity AS stock_quantity, stock.ytd AS stock_ytd, stock.order_cnt AS stock_order_cnt, stock.remote_cnt AS stock_remote_cnt, stock.data AS stock_dataFROM stockWHERE stock.warehouse_id = %(warehouse_id_1)s AND stock.item_id IN (%(item_id_1)s, %(item_id_2)s) ORDER BY id FOR UPDATE {‘warehouse_id_1’: 7, ‘item_id_1’: 53, ‘item_id_2’: 54}
그러나 분명히 SQLAlchemy는 다른 객체에 적용할 수 있기 때문에 전달 유형 트랜잭션을 더 빠르게 수행할 수 있습니다. 여러 UPDATE 작업이 하나로 결합되었습니다. 명령.
예:
INFO:www.zpedu.com/sqlalchemy.engine.base.Engine:UPDATE order_line SET delivery_d=% (delivery_d)s WHERE order_line.id = %(order_line_id)s INFO:sqlalchemy.engine.base.Engine:( {‘delivery_d’: datetime.datetime(2020, 4, 6, 14, 33, 6, 922281), ‘order_line_id’: 316}, {‘delivery_d’: datetime.datetime(2020, 4, 6, 14, 33, 6, 922272), ‘order_line_id’: 317}, {‘delivery_d’: datetime.datetime(2020, 4, 6, 14, 33, 6, 922261))
이 경우 Little A는 업데이트마다 별도의 쿼리를 보냅니다.
결론
테스트 결과에 따르면 포니가 데이터베이스에서 더 빠르게 선택한다고 할 수 있습니다. 반면에 어떤 경우에는 SQLAlchemy가 더 빠른 속도로 업데이트 유형 쿼리를 생성할 수 있습니다.
위 내용은 TPC-C 벤치마크 기반 Python ORM 성능 테스트에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!