加速并发轻量级SQL查询

时间:2017-03-15 03:44:46

标签: mysql performance concurrency database-administration amazon-rds-aurora

我有一个需要进行许多并发轻量级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_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);

# 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亿行的数据。

1 个答案:

答案 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