我知道如果表太大,索引很难适应buffer_pool, 所以使用索引可能会导致大量的随机磁盘IO。所以全表扫描, 通常,它可能比索引扫描快得多,即使它只读取大约%1行。
What I am confused about is :
[0] If there are a big table( 30 millions rows),and many small tables(each table can be fit into memory(buffer)),
will the big table also affect query about small tables ?
My logic is <======>
the buffer is shared by the whole database, so the big table will take most of buffer.
So the indexes of small tables can also hardly be fit into buffer(or it's often
removed from the buffer). Then the above conclusion(full table scan vs index scan) can be applied to this case .
[1] When the big table are partitioned into may small tables(in just one machine), the situation of buffer should keep identical.
So such partition cannot solve this problem(full table scan vs index scan), right? so the "big table" should not mean "one big table", but the "huge database or the sum of data is large"
总结一下,我的包容是对的吗?如果错了,为什么?请给我一个提示。非常感谢。
答案 0 :(得分:1)
所有表,数据和索引共享buffer_pool
。但你所说的其余内容需要关注“块”而不是“表”。
缓存是在块的基础上执行的。块(在InnoDB中)是16KB。大多数innodb_buffer_pool_size
专用于数据和索引块。
缓存作为 LRU (最近最少使用)运行(大约) - 也就是说,当需要其他块时,最近最少使用的块将从缓存中抛出。
不,表或索引没有“完全”加载到缓存中。而是在需要时加载(和清除)所需的块。
如果所有数据和索引都适合缓存,那么(最终)所有块都将“存在”那里。
如果数据加上索引太大,那么块将根据需要进出。 通常这几乎与将它们全部加载一样好。例如,如果您通常使用“最近”记录,那么包含它们的块将“保留”在缓存中;与此同时,“旧”街区将被淘汰出局。
如果您使用 UUID (GUID),性能可能会非常糟糕 - 这是因为此类索引值的随机性。
应该避免全表扫描(以及完整索引扫描),无论事情是否太大而无法容纳在缓存中。它们成本很高,通过适当的索引和/或查询表达式可以避免它们通常。
当你在比缓存更大的表上进行全表扫描时,必须给出一些东西。你将不得不做一些I / O,一些块将被缓存。但是,内置了一种技术可以防止盲目地清除整个缓存以进行偶尔的表扫描。进一步讨论,研究innodb_old_blocks_pct
。 (不,我不建议将其从默认的37%更改。)
分区表是什么意思?如果你的意思是内置PARTITION
机制,那么呢?如果您扫描表,则正在扫描所有分区。相同的数字块;对缓存的影响相同。
我已经将超过buffer_pool的表集处理了10倍或更多。我可以讨论性能技术,但我需要一个特定的SHOW CREATE TABLE
(有或没有PARTITIONs
)和一些顽皮的查询(例如表扫描)。
优化程序在执行表扫描和使用基于各种统计信息等的索引之间选择。如果需要触摸超过20%的行,则需要遵守规则,它将进行表扫描,而不是在索引和数据之间进行弹跳。 (注意:截止值远高于你提到的1%。)
索引在16KB块中构造为BTree
,因此从中间开始并扫描范围非常有效。例如:INDEX(last_name)
的{{1}}可能会对索引的10%进行“范围扫描”,即使这种情况涉及到很多时候都会反复出现。