我有一个非常复杂的搜索查询要编写,它将涉及许多表,具有条件和连接。出于效率原因,我强烈考虑创建一个“缓存表”,我可能每天计算一次大部分工作,这样当用户想要进行搜索时,它会更快。
然而,这个缓存表很容易有 10 到 5000 万行。这很糟糕吗?这值得吗?我会提高效率吗?我应该留意哪些事情?
我们使用 InnoDB。
目前正在研究重新索引我们的 sql 数据库,但找不到有关过程缓存是否会受到影响的任何信息。任何帮助或信息都会很棒。我们使用 SQL Server 2005 作为我们的 DBMS。
使用 SQL Server 2008 R2,供应商数据库中的主事务表与所有其他表相比非常庞大,大约有 14 个索引。其中一些索引不会在我们的环境中使用,但我们无法删除它们。这不是问题,这只是我们必须忍受的事情。
我的问题是为什么这些低读取或无读取索引中的一些似乎正在使用内存 - 比同一个大表上经常使用的其他索引更多。我原以为大部分缓冲区缓存都会用于频繁读取的对象。这些索引上发生的唯一事情是写开销。
例如,这些低读取索引中的一个分配了大约 2 GB 的内存(索引总大小的 58%),另一个分配了 1.7 GB 的内存(其大小的 27%)。同时,规模庞大且使用良好的聚集索引本身只有 4 个演出(其大小的 2%)。具有大量读取的不同 NC 索引在缓冲区缓存中只有 100 MB(其大小的 5%)。
查看物理统计数据,我可以看到碎片非常糟糕。从该表上的所有写入和非顺序插入可以理解这一点。不过,我不确定它是否与内存使用有关。
查看这些索引的操作统计数据也很有趣。
我意识到这是一个抽象的问题,我没有提供很多实际的统计数据。我只是好奇 SQL Server 如何做出这些缓冲区缓存使用决策,并想知道是否有人理解它。
我有一个包含大约 1000 万行的表,其中包含一个主键和一个定义在其上的索引:
create table test.test_table(
date_info date not null,
string_data varchar(64) not null,
data bigint
primary key(date_info, string_data));
create index test_table_idx
on test.test_table(string_data);
Run Code Online (Sandbox Code Playgroud)
我有一个使用了的查询test_table_idx:
select distinct date_info from test.test_table where string_data = 'some_val';
Run Code Online (Sandbox Code Playgroud)
问题是第一次运行查询最多可能需要 20 秒,而在任何后续运行中都需要 < 2 秒。
有没有办法将整个索引加载到内存中,而不是在第一次访问时获取数据库加载信息?
另一个问题来自我发现EXPLAINPostgreSQL 中很棒的新选项。这一项侧重于BUFFERS选项。
这里是EXPLAIN:
EXPLAIN (ANALYZE, BUFFERS) SELECT event_time FROM ui_events_v2 WHERE page ~ 'foo' LIMIT 1;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------
Limit (cost=0.00..1539.68 rows=1 width=8) (actual time=0.858..0.858 rows=1 loops=1)
Buffers: shared read=10
I/O Timings: read=0.735
-> Seq Scan on ui_events_v2 (cost=0.00..3313394.58 rows=2152 width=8) (actual time=0.857..0.857 rows=1 loops=1)
Filter: (page ~ 'foo'::text)
Rows Removed by Filter: 112
Buffers: shared read=10
I/O Timings: read=0.735
Planning Time: 6.455 ms
Execution Time: 0.877 ms
Run Code Online (Sandbox Code Playgroud)
它非常快 - 这个查询在冷启动时非常慢。这是一个 30M 的行表,有七行page …
我正在尝试调查为什么此查询的性能如此不确定。它可能需要 1 秒到 60 秒及以上的任何时间。查询的本质是选择一个“时间窗口”,并从该时间窗口内获取所有行。
这是有问题的查询,在大约 10 亿行的表上运行:
SELECT CAST(extract(EPOCH from ts)*1000000 as bigint) as ts
, ticks
, quantity
, side
FROM order_book
WHERE ts >= TO_TIMESTAMP(1618882633073383/1000000.0)
AND ts < TO_TIMESTAMP(1618969033073383/1000000.0)
AND zx_prod_id = 0
ORDER BY ts ASC, del desc;
Run Code Online (Sandbox Code Playgroud)
这就是表的创建方式
CREATE TABLE public.order_book
(
ts timestamp with time zone NOT NULL,
zx_prod_id smallint NOT NULL,
ticks integer NOT NULL,
quantity integer NOT NULL,
side boolean NOT NULL,
del boolean NOT NULL
)
Run Code Online (Sandbox Code Playgroud)
TO_TIMESTAMP当我走整张桌子时,其中的值将继续向前滑动。以下是EXPLAIN ANALYZE两个不同时间窗口上相同查询的输出: …
在my.cnf我有:
table_cache = 524288
open_files_limit = 65535
Run Code Online (Sandbox Code Playgroud)
两者都处于 mysql 配置的最大允许值。两者都小于最大打开文件限制:
# cat /proc/sys/fs/file-max
2097152
Run Code Online (Sandbox Code Playgroud)
MySQL 变量状态:
mysql> SHOW GLOBAL STATUS LIKE 'open%';
+--------------------------+--------+
| Variable_name | Value |
+--------------------------+--------+
| Open_files | 193 |
| Open_streams | 0 |
| Open_table_definitions | 594 |
| Open_tables | 802 |
| Opened_files | 537248 |
| Opened_table_definitions | 4895 |
| Opened_tables | 9174 |
+--------------------------+--------+
7 rows in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
服务器有 32GB 内存。大部分免费!
尽管如此,当我运行 mysqltuner 脚本时:
它说: …
很直接的问题:
假设我有一个我知道经常使用的特定查询,我可以告诉 MySQL 始终“自动”缓存它吗……即,一旦缓存的查询结果被刷新,mysqld立即再次运行该查询,以便为缓存数据做好准备下一个用户?
或者反过来:我可以告诉 MySQL 不缓存特定查询吗?其他缓存选项呢,不一定与查询相关?
我在网上搜索了这个,但找不到任何相关的东西。
我正在使用AWS Aurora PostgreSQL Serverless自动缩放。看起来好像缩放清除了共享缓冲区,所以当我们想要提高性能时,我们被迫面对 I/O 瓶颈。在我们热身之后,我们看到了巨大的性能提升。但是,如果我们在缩放后背靠背运行,则第二次运行会更快。虽然我没有看到任何关于共享缓冲区是否在缩放时被清除的具体信息,但我几乎肯定它是。
Aurora Serverless 目前正在使用PostgreSQL 10.14,并且支持pg_prewarm扩展。它看起来像最新的文件显示在服务器重新启动后prewarm支持自动prewarm,但这是无服务器并不会出现提自动预暖的一个版本的文档中。
我发现这篇文章在重新启动服务器或从崩溃中恢复时非常适合 PostgreSQL。
pg_prewarm支持first_block和last_block阻止表/索引的编号,但是如何知道要放入哪些值呢?我们提前知道我们的峰值是什么时候,并告诉 RDS 在此之前进行扩展,因此我们有一个可以准备的时间窗口。
我有哪些选择?
我正在阅读Oracle 概念文档并有疑问 [关于一般缓存机制]:
PL/SQL 函数代码可以包括缓存其结果的请求。调用此函数时,系统会检查缓存。如果缓存包含具有相同参数值的先前函数调用的结果,则系统将缓存的结果返回给调用者并且不重新执行函数体。如果缓存中不包含结果,则系统执行函数体并将结果(对于这些参数值)添加到缓存中,然后再将控制权返回给调用者
我的疑问:
执行 PL/SQL 函数后,其结果集存储在缓存中。然后 DDL 语句更改表/索引/函数使用的任何内容...
如果我现在运行相同的 PL/SQL 函数,我会得到相同的结果还是更新的结果?
我想将整个数据库加载到内存中,但是我该怎么做呢?我有大约 256 GB 的内存,我的数据库大约有 200 GB,所以我可以轻松地处理内存。
当我执行select count(*) from table1sqlserver 自动将表加载到内存之后,我可以非常快速地使用表,但我想知道如何将整个数据库加载到内存中?
如果我select count(*) from在每个表上都这样做,我可以更快地工作,但是有没有其他方法可以将整个数据库加载到内存中?我想通过一个命令加载整个数据库,而不是一个select count(*) from表一个表。
cache ×11
postgresql ×4
mysql ×3
index ×2
memory ×2
optimization ×2
sql-server ×2
aws-aurora ×1
buffer-pool ×1
explain ×1
innodb ×1
my.cnf ×1
oracle ×1
performance ×1
plsql ×1
query-cache ×1
timescaledb ×1