我有一个需要进行许多并发轻量级SQL查询的应用程序。例如 - 单位查询就像"对于这家商店,今天按类别给我一份销售清单。"单独这个查询非常便宜 - 最多运行几十毫秒。
我需要在商店级别执行此查询 - "对于此商店组的每笔交易(大约最多30个),请按类别列出销售清单。"这显然可以作为组中商店集的连接实现 - 但这太慢了。它与交易数量成比例放缓(实际上,与购买的商品总数成比例)。
相反,我已将它实现为许多并发存储级查询(我将批量大小改为无效)然后我将结果合并到应用程序层中。这种方法运行得相当好,特别是与PreparedStatements结合使用时。不幸的是,这还不够快。在大多数情况下,这需要5-15秒到0.5-1.5秒的查询时间,但有时需要3秒,这超出了可接受的性能范围(小于2秒)。
信息不可缓存,因为在可接受的缓存时间范围内不太可能执行相同的查询。请注意,最近过去(两周左右)的查询执行速度非常快 - 因为数据库写入会将数据部分保留在DB / OS缓存中。它的随机读取是杀手锏。
您是否有任何DB向导有任何提示来加快此查询过程?我对SQL很陌生,我办公室里的任何人都没有尝试过这样的事情。我已经对它们进行了基准测试和计时,我非常确定它可以同时分解多达100个查询(30 * 3指标+一些简单的查询),这让我花费了大量时间。查询时间列表看起来像[10, 15, 30, 55, 89, 100, 300, ..., 1599]
,所有时间都只在execute()
调用附近。作为参考,我使用Java作为应用程序语言,使用C3P0和500-1000开放数据库连接,使用Amazon Aurora作为数据库。我甚至尝试在两个读取副本上对100个查询进行负载平衡,但这似乎只是名义上提高了性能,这让我感到沮丧。我认为TRANSACTION_READ_UNCOMMITTED
和SCROLL_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);
# used for querying
CREATE UNIQUE INDEX store_date_transaction_id_idx
ON ticket (store_id, business_date, transaction_id);
CREATE INDEX store_id_idx
ON transaction (store_id);
CREATE INDEX date_idx
ON transaction (business_date);
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
表有一年超过7亿行的数据。
答案 0 :(得分: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。