[英]mariadb not using the correct index with subquery
我在mariadb數據庫上遇到性能問題。 在我看來,mariadb在使用子查詢進行請求時未使用正確的索引,而在請求中手動注入子查詢的結果則成功使用了索引:
這是行為不良的請求(請注意,第二個子查詢讀取的行多於必要的行):
ANALYZE SELECT `orders`.* FROM `orders`
WHERE `orders`.`account_id` IN (SELECT `accounts`.`id` FROM `accounts` WHERE `accounts`.`user_id` = 88144)
AND ( orders.type not in ("LimitOrder", "MarketOrder")
OR orders.type in ("LimitOrder", "MarketOrder") AND orders.state <> "canceled"
OR orders.type in ("LimitOrder", "MarketOrder") AND orders.state = "canceled" AND orders.traded_btc > 0 )
AND (NOT (orders.type = 'AdminOrder' AND orders.state = 'canceled')) ORDER BY `orders`.`id` DESC LIMIT 20 OFFSET 0 \G;
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table: accounts
type: ref
possible_keys: PRIMARY,index_accounts_on_user_id
key: index_accounts_on_user_id
key_len: 4
ref: const
rows: 7
r_rows: 7.00
filtered: 100.00
r_filtered: 100.00
Extra: Using index; Using temporary; Using filesort
*************************** 2. row ***************************
id: 1
select_type: PRIMARY
table: orders
type: ref
possible_keys: index_orders_on_account_id_and_type,index_orders_on_type_and_state_and_buying,index_orders_on_account_id_and_type_and_state,index_orders_on_account_id_and_type_and_state_and_traded_btc
key: index_orders_on_account_id_and_type_and_state_and_traded_btc
key_len: 4
ref: bitcoin_central.accounts.id
rows: 60
r_rows: 393.86
filtered: 100.00
r_filtered: 100.00
Extra: Using index condition; Using where
當手動注入子查詢的結果時,我具有正確的行為(和預期的性能):
ANALYZE SELECT `orders`.* FROM `orders`
WHERE `orders`.`account_id` IN (433212, 433213, 433214, 433215, 436058, 436874, 437950)
AND ( orders.type not in ("LimitOrder", "MarketOrder")
OR orders.type in ("LimitOrder", "MarketOrder") AND orders.state <> "canceled"
OR orders.type in ("LimitOrder", "MarketOrder") AND orders.state = "canceled" AND orders.traded_btc > 0 )
AND (NOT (orders.type = 'AdminOrder' AND orders.state = 'canceled'))
ORDER BY `orders`.`id` DESC LIMIT 20 OFFSET 0\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: orders
type: range
possible_keys: index_orders_on_account_id_and_type,index_orders_on_type_and_state_and_buying,index_orders_on_account_id_and_type_and_state,index_orders_on_account_id_and_type_and_state_and_traded_btc
key: index_orders_on_account_id_and_type_and_state_and_traded_btc
key_len: 933
ref: NULL
rows: 2809
r_rows: 20.00
filtered: 100.00
r_filtered: 100.00
Extra: Using index condition; Using where; Using filesort
1 row in set (0.37 sec)
請注意,加入兩個表時,我有完全相同的問題。
這是我的訂單表的定義的摘錄:
SHOW CREATE TABLE orders \G;
*************************** 1. row ***************************
Table: orders
Create Table: CREATE TABLE `orders` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`account_id` int(11) NOT NULL,
`traded_btc` decimal(16,8) DEFAULT '0.00000000',
`type` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`state` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `index_orders_on_account_id_and_type_and_state_and_traded_btc` (`account_id`,`type`,`state`,`traded_btc`),
CONSTRAINT `orders_account_id_fk` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=8575594 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
有人知道這是怎么回事嗎? 有沒有一種方法可以強制數據庫在子請求中使用我的索引。
IN ( SELECT ... )
優化效果不佳。 通常的解決方案是將JOIN
變成:
FROM accounts AS a
JOIN orders AS o ON a.id = o.account_id
WHERE a.user_id = 88144
AND ... -- the rest of your WHERE
還是您對“請注意,在合並兩個表時遇到完全相同的問題”的做法是? 如果是這樣,讓我們看一下查詢,它是EXPLAIN
。
您指的是“預期的性能” ...您指的是EXPLAIN
的數字嗎? 還是您有時間備份聲明?
我喜歡這樣做,以便更好地了解正在進行的“工作”量:
FLUSH STATUS;
SELECT ...;
SHOW SESSION STATUS LIKE 'Handler%';
這些數字通常可以清楚地表明是否涉及表掃描或在OFFSET+LIMIT
之后查詢是否停止。 這些數字是精確的計數,與EXPLAIN
不同,后者只是估計值。
大概您通常通過account_id
查找orders
? 這是加快此類查詢速度的一種方法:
替換當前的兩個索引
PRIMARY KEY (`id`),
KEY `account_id__type__state__traded_btc`
(`account_id`,`type`,`state`,`traded_btc`),
用這些:
PRIMARY KEY (`account_id`, `type`, `id`),
KEY (id) -- to keep AUTO_INCREMENT happy.
這會聚集給定帳戶的所有行,從而使查詢運行更快,尤其是如果您現在受 I / O限制。 如果某些列組合形成“自然” PK,則完全折騰id
。
(請注意,我如何在不丟失任何信息的情況下縮短了您的鍵名?)
另外,如果您受I / O約束,則可以通過將那些冗長的VARCHARs
(狀態和類型)轉換為ENUMs
縮小表。
更多
鑒於查詢涉及
WHERE ... mess with INs and ORs ...
ORDER BY ...
LIMIT 20
並且該用戶有200萬行,沒有INDEX
可以通過WHERE
進入ORDER BY
,從而可以使用LIMIT
。 也就是說,它必須以這種方式執行:
ORDER BY
)2M行的相當大的一部分 實際上,我驚訝於IN( constants )
運作良好。
我有同樣的問題。 請使用內部聯接而不是子查詢。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.