我看起来像一个相当简单的表结构,但MySQL index_merge在一个简单的查询中默认为不是最优的.
这是表结构:
CREATE TABLE IF NOT EXISTS `event_log` (
`event_id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(5) DEFAULT NULL,
`location_id` int(10) DEFAULT NULL,
`object_id` int(5) DEFAULT NULL,
`action_id` int(5) DEFAULT NULL,
`date_event` datetime DEFAULT NULL,
PRIMARY KEY (`event_id`),
KEY `user_id` (`user_id`),
KEY `date_event` (`date_event`),
KEY `action_id` (`action_id`),
KEY `object_id` (`object_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Run Code Online (Sandbox Code Playgroud)
解析一个基本的SELECT查询
EXPLAIN SELECT date_event
FROM event_log
WHERE user_id =123
AND object_id =456
AND location_id =789
Run Code Online (Sandbox Code Playgroud)
返回此:
select_type table type possible_keys key key_len ref rows Extra …Run Code Online (Sandbox Code Playgroud) 查询在具有1,100万行的大型表上执行.我已经ANALYZE在查询执行之前在表上执行了一个.
查询1:
SELECT *
FROM accounts t1
LEFT OUTER JOIN accounts t2
ON (t1.account_no = t2.account_no
AND t1.effective_date < t2.effective_date)
WHERE t2.account_no IS NULL;
Run Code Online (Sandbox Code Playgroud)
解释分析:
Hash Anti Join (cost=480795.57..1201111.40 rows=7369854 width=292) (actual time=29619.499..115662.111 rows=1977871 loops=1)
Hash Cond: ((t1.account_no)::text = (t2.account_no)::text)
Join Filter: ((t1.effective_date)::text < (t2.effective_date)::text)
-> Seq Scan on accounts t1 (cost=0.00..342610.81 rows=11054781 width=146) (actual time=0.025..25693.921 rows=11034070 loops=1)
-> Hash (cost=342610.81..342610.81 rows=11054781 width=146) (actual time=29612.925..29612.925 rows=11034070 loops=1)
Buckets: 2097152 Batches: 1 Memory Usage: 1834187kB
-> Seq Scan on …Run Code Online (Sandbox Code Playgroud) sql postgresql explain database-performance sql-execution-plan
我有桌子items和桌子item_attributes.
为简单起见,假设我的表项有一列id和一列name.对于cource,id列上有一个索引.
该item_attributes表具有的列id,item_id,attribute_name和attribute_value和索引ONattrubute_name
现在我想查询具有特定属性的所有项目而不使用连接.
我使用以下查询执行此操作:
SELECT *
FROM items i
WHERE i.id IN (
SELECT item_id
FROM item_attributes a
WHERE a.attribute_name = 'SomeAttribute'
AND a.attribute_value = 'SomeValue'
)
Run Code Online (Sandbox Code Playgroud)
SubQuery本身运行得很快.
如果我首先执行查询本身并将结果用于IN查询
SELECT *
FROM items i
WHERE i.id IN (1,3,5,7,10,...)
Run Code Online (Sandbox Code Playgroud)
它也很快.
但是,组合查询非常非常慢(> 2秒).如果我调查查询计划,我明白为什么:MySQL对items表执行全表扫描,而不是先执行子查询并使用结果进行索引查询.
1, 'PRIMARY', 'items', 'ALL', '', '', '', '', 149726, 'Using where'
2, 'DEPENDENT SUBQUERY', 'item_attributes', 'index_subquery', 'IDX_ATTRIBUTE_NAME', …Run Code Online (Sandbox Code Playgroud) 我有一个简单的邀请表:
CREATE TABLE `invitation` (
`invitation_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`inviter_id` int(10) unsigned NOT NULL,
`invitee_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`invitation_id`),
UNIQUE KEY `invitee_inviter_idx` (`invitee_id`,`inviter_id`)
)
Run Code Online (Sandbox Code Playgroud)
我想通过邀请者70选择被邀请者62的邀请,反之亦然:
EXPLAIN SELECT * FROM `invitation` WHERE
(invitee_id = 70 AND inviter_id = 62) OR (invitee_id = 62 AND inviter_id = 70)
Run Code Online (Sandbox Code Playgroud)
但是此查询的类型为ALL,并且不使用invitee_inviter_idx.请告诉我这里有什么问题?
谢谢!
==编辑==对不起,我错了架构,还有一个字段:request_ts.这次查询计划是ALL.
CREATE TABLE `invitation` (
`invitation_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`inviter_id` int(10) unsigned NOT NULL,
`invitee_id` int(10) unsigned NOT NULL,
`request_ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, …Run Code Online (Sandbox Code Playgroud) 我有3个innodb表,比如说A,B和C.有一个查询可以连接这三个表来生成结果.
SELECT A.a, B.b, C.c
from A
join B on A.id = B.a_id
join C on C.id = B.c_id
where A.a = 'example' and B.b < 10;
Run Code Online (Sandbox Code Playgroud)
在我使用'EXPLAIN'命令测试查询时,它给出了以下顺序:
B - C - A.
但是,这不是最佳的.所以我对所有表运行'ANALYZE TABLE',它给了我:
A - B - C.
,我相信这是正确的顺序.
然后我将SQL部署到生产中,并且无缘无故地,在1个月之后,执行计划切换回坏选项,即B-C-A.在那之后,我尝试了多次ANALYZE TABLE再次运行,但这一次,结果让我感到困惑.有时它也会给我B - C - A,有时它会给我A - B - C,有时甚至是其他执行计划.
所以我的问题是:
我需要知道特定查询将运行多长时间(我预计运行时间非常长).为此,我决定EXPLAIN ANALYZE在查询集上运行一个只包含整个数据集的一部分并从那里进行推断.但我有一个问题; 在连接超时之前,查询需要两个多小时,没有结果.我不想增加超时,因为我不知道可以运行多长时间(两小时到两天之间).
有没有办法可以指示SQL服务器将数据输出到服务器文件系统上的文件中,所以我不必担心超时?我尝试过以下方法:
Copy (
EXPLAIN ANALYZE INSERT INTO <table>
<Long complex query here>
) To '/tmp/analyze.csv' With CSV;
Run Code Online (Sandbox Code Playgroud)
但我得到一个错误EXPLAIN.
为了记录,是的,我想这样做ANALYZE是因为
在MySQL的5.7文档状态:
该
filtered列指示将由表条件过滤的表行的估计百分比。也就是说,rows显示估计的检查行数并rows × filtered / 100显示将与先前表连接的行数。
为了更好地理解这一点,我在使用MySQL Sakila 示例数据库的查询中进行了尝试。有问题的表具有以下结构:
mysql> SHOW CREATE TABLE film \G
*************************** 1. row ***************************
Table: film
Create Table: CREATE TABLE `film` (
`film_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`description` text,
`release_year` year(4) DEFAULT NULL,
`language_id` tinyint(3) unsigned NOT NULL,
`original_language_id` tinyint(3) unsigned DEFAULT NULL,
`rental_duration` tinyint(3) unsigned NOT NULL DEFAULT '3',
`rental_rate` decimal(4,2) NOT NULL DEFAULT '4.99',
`length` smallint(5) unsigned DEFAULT …Run Code Online (Sandbox Code Playgroud) 我成功运行:
result = my_col.aggregate(my_pipeline, allowDiskUse=True)
Run Code Online (Sandbox Code Playgroud)
现在,当我尝试:
result = my_col.aggregate(my_pipeline, allowDiskUse=True, explain=True)
Run Code Online (Sandbox Code Playgroud)
它没有说:
pymongo.errors.ConfigurationError: The explain option is not supported. Use Database.command instead.
Run Code Online (Sandbox Code Playgroud)
因此,我尝试添加所需的选项:
result = mydb.command('aggregate', 'mycol', my_pipeline, {'explain':True})
Run Code Online (Sandbox Code Playgroud)
但失败说:
pymongo.errors.OperationFailure: 'pipeline' option must be specified as an array
Run Code Online (Sandbox Code Playgroud)
怎么了?
感谢您的任何建议。
基督教
sqlite> .schema actor
CREATE TABLE actor (
id INTEGER PRIMARY KEY, name TEXT, gender TEXT
);
sqlite> explain query plan
...> select * from actor where id = '305453';
0|0|0|SEARCH TABLE actor USING INTEGER PRIMARY KEY (rowid=?)
sqlite> explain query plan
...> select * from actor where name = 'Connery, Sean';
0|0|0|SCAN TABLE actor
sqlite>
Run Code Online (Sandbox Code Playgroud)
SEARCH TABLE actor USING INTEGER PRIMARY KEY (rowid=?)与相比,花费的时间明显更少SCAN TABLE actor
很明显,由于重复的可能性,这SCAN TABLE actor是对表的彻底扫描,但是,actor
1)SCAN TABLE&SEARCH TABLE扫描B-TREE还是记录序列? …
尽管标题列是通过使用以下查询添加为索引的:
ALTER TABLE Recipe ADD INDEX Title_idx (Title)
Run Code Online (Sandbox Code Playgroud)
MySQL 不使用该索引来执行此查询:
SELECT * FROM Recipe
WHERE Title LIKE '%cake%';
Run Code Online (Sandbox Code Playgroud)
我使用了EXPLAIN关键字,关键字段是NULL。
怎么解决呢?我必须改进该查询。