我最近听到很多,我应该看看我的SQL的执行计划,以判断它的执行情况.但是,我不确定从何处开始使用此功能或具体含义.
我正在寻找一个很好的解释执行计划的作用,它的局限性,以及我如何利用它或指向一个资源.
试图在SQL Developer中生成解释计划,程序会弹出一个消息框,标题为"无法查询plan_table",抱怨"无效的列名".未生成或显示该计划.怎么修?
我希望这两个SELECTs具有相同的执行计划和性能.由于有一个领先的通配符LIKE,我希望进行索引扫描.当我运行它并查看计划时,第一个SELECT按预期运行(使用扫描).但第二个SELECT计划显示索引搜索,并且运行速度提高了20倍.
码:
-- Uses index scan, as expected:
SELECT 1
FROM AccountAction
WHERE AccountNumber LIKE '%441025586401'
-- Uses index seek somehow, and runs much faster:
declare @empty VARCHAR(30) = ''
SELECT 1
FROM AccountAction
WHERE AccountNumber LIKE '%441025586401' + @empty
Run Code Online (Sandbox Code Playgroud)
题:
当模式以通配符开头时,SQL Server如何使用索引查找?
奖金问题:
为什么连接空字符串会改变/改进执行计划?
细节:
Accounts.AccountNumberAccounts.AccountNumber列可以为空varchar(30)表和索引定义:
CREATE TABLE [updatable].[AccountAction](
[ID] [int] IDENTITY(1,1) NOT NULL,
[AccountNumber] [varchar](30) NULL,
[Utility] [varchar](9) …Run Code Online (Sandbox Code Playgroud) 我有一个参数化查询。根据参数值的不同,最优查询计划会有很大差异。问题在于:Oracle 将第一次查询调用的计划用于后续调用,从而导致性能不佳。我通过动态 SQL 处理它,但这种方式远非优雅。所以问题是:有没有办法告诉 Oracle 必须重新计算查询计划?
我有三张桌子:
SmallTable
(id int, flag1 bit, flag2 bit)
JoinTable
(SmallTableID int, BigTableID int)
BigTable
(id int, text1 nvarchar(100), otherstuff...)
Run Code Online (Sandbox Code Playgroud)
SmallTable最多只有几十条记录.BigTable有几百万,实际上是一个视图,UNIONS在这个数据库中的一个表与同一服务器上的另一个数据库中的表.
这是连接逻辑:
SELECT * FROM
SmallTable s
INNER JOIN JoinTable j ON j.SmallTableID = s.ID
INNER JOIN BigTable b ON b.ID = j.BigTableID
WHERE
(s.flag1=1 OR b.text1 NOT LIKE 'pattern1%')
AND (s.flag2=1 OR b.text1 <> 'value1')
Run Code Online (Sandbox Code Playgroud)
平均连接大小是几千个结果.显示的所有内容都已编入索引.
对于大多数SmallTable记录,flag1并flag2设置为1,所以实际上甚至不需要访问BigTable.text1上的索引,但SQL Server无论如何都会这样做,导致代价高昂的索引扫描和嵌套循环.
有没有更好的方式来暗示到SQL Server,如果flag1和flag2都被设置为1,它不应该甚至懒得看text1?
实际上,如果我可以在这些情况下完全避免加入BigTable(管理JoinTable,这不会产生问题),这将使这个关键查询更快.
t-sql sql-server performance short-circuiting sql-execution-plan
如果我在SSMS中运行此命令:
set showplan_xml on
GO
exec some_procedure 'arg1', 'arg2','arg3'
GO
set showplan_xml off
GO
Run Code Online (Sandbox Code Playgroud)
我获得了查询执行中涉及的完整调用堆栈的XML输出,以及任何建议的索引等.
怎么可能从C#中读到这个?
(一个用例可能是定期启用此功能并在生产环境中记录这些结果,以便密切关注索引建议.)
我遇到的问题是,索引的查询拒绝使用索引,因为它没有足够的选择性(假设有1.3亿行中的60个符合条件),因此决定使用seqscan.
我面临的问题是seqscan在这种情况下真的不是最好的选择,由于某些原因它获得了非常好的分数,但事实是seqscan只有在之前被查询并且它可以加载所有内容时才能快速运行来自缓冲区/缓存.
与seqscan相比,索引扫描可能稍微慢一点,如果它们的两个都在缓冲区上,但这很少发生,当两个查询都很冷时,索引扫描仍然更快(ms vs秒).
请注意,索引扫描是优越的,因为我正在使用限制子句,因此它应该能够非常快速地获取这几行.
我已将统计值设置为1000(默认值为100)并且为了以防真空吸尘,但是相同的故事.
TLDR:Seq扫描与低选择性索引上的索引扫描,seqscan是首选,但规划者是错误的,seqscan只有在缓存时才会更好,否则会更糟.
查询和计划,请注意索引一是从缓冲区加载而seqscan不完全.
explain (analyze, buffers)
select *
from identities_identity
where email_domain = 'live.com'
limit 100
'Limit (cost=0.00..63.50 rows=100 width=573) (actual time=75215.573..75215.640 rows=100 loops=1)'
' Buffers: shared hit=75113 read=588870'
' -> Seq Scan on identities_identity (cost=0.00..2980008.00 rows=4692733 width=573) (actual time=75215.571..75215.604 rows=100 loops=1)'
' Filter: ((email_domain)::text = 'live.com'::text)'
' Rows Removed by Filter: 54464136'
' Buffers: shared hit=75113 read=588870'
'Planning time: 0.097 ms'
'Execution time: 75215.675 ms'
'Limit (cost=0.57..187.26 rows=100 width=573) (actual time=0.027..0.090 rows=100 loops=1)'
' …Run Code Online (Sandbox Code Playgroud) 我正在使用数据库客户端来测试。
使用EXPLAIN ANALYZE:
Hash Join (cost=5.02..287015.54 rows=3400485 width=33) (actual time=0.023..1725.842 rows=3327845 loops=1)
Hash Cond: ((fact_orders.financial_status)::text = (include_list.financial_status)::text)
CTE include_list
-> Result (cost=0.00..1.77 rows=100 width=32) (actual time=0.003..0.004 rows=4 loops=1)
-> ProjectSet (cost=0.00..0.52 rows=100 width=32) (actual time=0.002..0.003 rows=4 loops=1)
-> Result (cost=0.00..0.01 rows=1 width=0) (actual time=0.000..0.000 rows=1 loops=1)
-> Seq Scan on fact_orders (cost=0.00..240253.85 rows=3400485 width=38) (actual time=0.006..551.558 rows=3400485 loops=1)
-> Hash (cost=2.00..2.00 rows=100 width=32) (actual time=0.009..0.009 rows=4 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 9kB
-> CTE Scan on …Run Code Online (Sandbox Code Playgroud) sql postgresql query-optimization explain sql-execution-plan
假设我想查询一个带有几个WHERE过滤器的大表。我正在使用 Postgres 11 和外部表;外部数据包装器 (FDW) 是clickhouse_fdw. 但我也对通用解决方案感兴趣。
我可以这样做:
SELECT id,c1,c2,c3 from big_table where id=3 and c1=2
Run Code Online (Sandbox Code Playgroud)
我的 FDW 能够对远程外部数据源进行过滤,确保上述查询快速并且不会拉取太多数据。
如果我写的话上面的效果是一样的:
SELECT id,c1,c2,c3 from big_table where id IN (3,4,5) and c1=2
Run Code Online (Sandbox Code Playgroud)
即所有的过滤都被发送到下游。
但是,如果我尝试执行的过滤稍微复杂一些:
SELECT bt.id,bt.c1,bt.c2,bt.c3
from big_table bt
join lookup_table l on bt.id=l.id
where c1=2 and l.x=5
Run Code Online (Sandbox Code Playgroud)
然后查询规划器决定远程过滤c1=2,但在本地应用另一个过滤器。
在我的用例中,先计算哪些ids 有l.x=5,然后将其发送出去进行远程过滤会快得多,所以我尝试按以下方式编写:
SELECT id,c1,c2,c3
from big_table
where c1=2
and id IN (select id from lookup_table where x=5)
Run Code Online (Sandbox Code Playgroud)
big_table然而,查询规划器仍然决定在本地对satisfy的所有结果执行第二个过滤器c1=2,这非常慢。
有什么方法可以“强制”(select …
sql postgresql sql-execution-plan postgresql-performance foreign-data-wrapper
根据MySQL文档,使用where意味着:WHERE子句用于限制哪些行与下一个表匹配或发送到客户端。
据我了解,这意味着如果您的sql语句有where条件,则您的解释中会出现“Using where”额外信息。根据我的经验,这似乎意味着 MySQL 存储引擎发现索引无法覆盖某些列,并且必须检索行数据。例如:
谁能解释一下Using where的真正含义?
postgresql ×3
sql ×3
sql-server ×3
explain ×2
oracle ×2
performance ×2
t-sql ×2
c# ×1
database ×1
indexing ×1
mysql ×1
seq ×1
sql-like ×1
sqlclr ×1
wildcard ×1