-1

많은 동시 경량 SQL 쿼리를 작성해야하는 응용 프로그램이 있습니다. 예를 들어, 단위 쿼리는 "이 상점에서 오늘 카테고리 별 판매 목록을 제공하십시오"와 같습니다. 이 쿼리만으로도 매우 저렴합니다. 수십 밀리 초 만에 실행됩니다.Concurrent Lightweight SQL 쿼리 속도 향상

"이 저장소 그룹의 모든 트랜잭션 (약 30 개까지)에 대해 오늘 범주별로 판매 목록을 제공하십시오."라는 상점 수준에서이 쿼리를 수행해야합니다. 이것은 분명히 그룹의 상점 집합에 대한 조인으로 구현 가능하지만 너무 느립니다. 거래 횟수에 비례하여 속도가 느려집니다 (실제로는 구매 한 총 상품 수에 비례하여).

대신 배치 수준의 쿼리를 여러 동시 저장소 쿼리로 구현했습니다 (배치 크기를 실제 사용 불가능으로 변경했습니다). 그런 다음 결과를 응용 프로그램 계층에 병합합니다. 이것은 특히 PreparedStatements와 결합 할 때 상당히 잘 작동합니다. 불행히도 이것은 충분히 빠르지 않습니다. 대부분의 시간 동안 쿼리 시간이 5-15 초에서 0.5-1.5 초까지 걸리지 만 가끔 허용되는 성능 범위 (2 초 미만) 밖에있는 경우에는 3 초가 걸릴 수 있습니다.

정보는 허용 가능한 캐싱 시간 프레임 내에서 동일한 쿼리가 실행되지 않을 가능성이 있으므로 캐시 할 수 없습니다. 최근 과거 (2 주 정도)에 대한 쿼리는 매우 빠르게 수행됩니다. DB가 데이터의 해당 섹션을 DB/OS 캐시에 최신 상태로 유지하기 때문입니다. 그것은 무작위로 읽혀 살인자입니다.

DB 마법사 중 누가이 쿼리 프로세스의 속도를 높이는 데 도움이 될까요? 나는 SQL에 익숙하지 않으며 내 사무실의 아무도 이전과 같은 것을 시도하지 않았다. 저는 벤치마킹을하고 철저히 시간을 잰 적이 있습니다. 동시에 100 개의 쿼리 (30 * 3 메트릭 + 몇 가지 간단한 쿼리)의 스핀 오프 (spin-off)가 동시에 시간 낭비라고 확신합니다. 쿼리 시간 목록은 [10, 15, 30, 55, 89, 100, 300, ..., 1599]처럼 표시되며 모두 execute() 호출 시간에 대해서만 계산됩니다. 참고로 C3P0 및 500-1000 개방형 DB 연결과 Amazon Aurora를 DB로 사용하여 Java를 응용 프로그램 언어로 사용하고 있습니다. 나는 심지어 두 개의 읽기 복제본에 걸쳐 100 개의 쿼리를로드 밸런싱하려했지만, 이것은 명목상 명목상으로 성능을 향상시키는 것으로 보인다. 나는 작은 성능 향상을 TRANSACTION_READ_UNCOMMITTEDSCROLL_INSENSITIVE + READ_ONLY으로 생각합니다.

편집 : 일부 테이블 구조 및 쿼리 (이름을 용서하십시오. transaction - 실제로이 이름을 사용하지는 않지만 업무상 이유로 변경했습니다.)

CREATE TABLE IF NOT EXISTS item ( item_id BIGINT UNSIGNED AUTO_INCREMENT, item_name VARCHAR(120), unit_price DECIMAL (10,2), PRIMARY KEY (item_id) ) ENGINE=INNODB;

CREATE TABLE IF NOT EXISTS transaction_item_list ( ticket_transaction_id BIGINT UNSIGNED AUTO_INCREMENT, transaction_id BIGINT UNSIGNED, item_id BIGINT UNSIGNED, item_quantity DECIMAL(10,2), item_sales DECIMAL(10,2), FOREIGN KEY (item_id) REFERENCES item (item_id), FOREIGN KEY (transaction_id) REFERENCES transaction (transaction_id), PRIMARY KEY (transaction_item_id) ) ENGINE=INNODB;

CREATE INDEX transaction_id_idx ON transaction_item_list (transaction_id);

CREATE INDEX item_id_idx ON transaction_item_list (item_id);

CREATE TABLE IF NOT EXISTS transaction ( transaction_id BIGINT UNSIGNED AUTO_INCREMENT, native_transaction_id VARCHAR(36) NOT NULL, store_id BIGINT UNSIGNED NOT NULL, server_time DATETIME NOT NULL, business_date DATE NOT NULL, FOREIGN KEY (store_id) REFERENCES store (store_id), PRIMARY KEY (transaction_id) ) ENGINE=INNODB;

# used for insertion CREATE UNIQUE INDEX store_date_native_transaction_id_idx ON ticket (store_id, business_date, native_transaction_id);

01,235

CREATE INDEX server_time_idx ON transaction (server_time);

SELECT sum(transaction_item_list.item_quantity * item.unit_price) FROM transaction_item_list JOIN item USING (item_id) JOIN transaction USING (transaction_id) WHERE (transaction.store_id, transaction.transaction_date) IN ((?, ?)) GROUP BY category;

transaction_item_list 테이블의 데이터 일년의 가치에 대한 만 700 행이

CREATE INDEX date_idx ON transaction (business_date);

CREATE INDEX store_id_idx ON transaction (store_id);

# used for querying CREATE UNIQUE INDEX store_date_transaction_id_idx ON ticket (store_id, business_date, transaction_id);

16,.

+0

테이블 구조와 몇 가지 샘플 쿼리를 제공해주십시오. –

+0

@ 모하메드 야신이 추가되었습니다. –

+0

관련 테이블에 대해 'SHOW CREATE TABLE'을 제공하십시오 (설명이 충분하지 않습니다). –

답변

0

이 구조체를 사용하지 마십시오. WHERE (store_id, transaction_date) IN ((?, ?)); 그것은 잘 최적화되지 않습니다. 대신,

WHERE store_id = ? 
    AND transaction_date = ? 

테이블 이름 (또는 별명)와 JOIN에 언급 된 각 열을 자격을하시기 바랍니다 사용; 독자 (우리)가 어디에서 왔는지 파악하는 것은 지루합니다.

인덱스는 필요 : 많은 매핑 (플러스 여분의 열) :

transaction: INDEX(store_id, transaction_date) -- in that order 
transaction_item_list: INDEX(transaction_id) -- if not already there 

transaction_item_list는 많은 냄새. 그렇다면 내 7 tips on many:many을 참조하십시오.

+0

나는 두 인덱스를 가지고있다 - 실제로 (store_id, transaction_date, )에 인덱스를 가지고 있으며, MySQL은 처음 11 비트 정도만 사용한다고 말한다. –

+0

그리고'IN ((?,?))'이 실제로 더 잘 최적화 된 큰 테이블에서 버그를 들었습니다. 두 경우 모두 최적화가 불량한 이유 또는 이유에 대해 권장되는 독서가 있습니까? –

+0

데이터베이스 설정에 나타나는 표 정의 및 색인 작성이 추가되었습니다. 조인은 'USING'으로 열 이름이 두 테이블에서 동일 함을 나타냅니다. –