准备好的语句,具有 1 亿条记录的 MyISAM 和 MySQL 上的缓存

Prepared Statements, MyISAM with 100 million records and Caching on MySQL

我有 10 个大型只读表。我做了很多具有相同格式但参数不同的查询,例如:

SELECT 'count' FROM table1 WHERE x='SOME VARIABLE';
SELECT 'count' FROM table1 WHERE x='SOME OTHER VARIABLE';
...
SELECT 'count' FROM table2 WHERE x='' AND y='';
SELECT 'count' FROM table2 WHERE x='' AND y='';
...
SELECT 'count' FROM table3 WHERE x='' AND y='' AND z='';

每个查询使用的变量都不同,所以我几乎从不执行同一个查询两次。 MySQL 端的查询缓存和行缓存会造成浪费并且应该禁用它们是否正确? Table 缓存似乎是一件好事。

在客户端,我使用的是准备好的语句,我认为这是好的。如果我启用 Prepared statement 缓存(通过 Slick),那不会损害我的性能,因为参数变化很大吗?我还能做些什么来优化我的表现吗?

是否应该关闭自动提交,因为我只是在做选择,永远不需要回滚?

鉴于您使用的是 MYISAM 引擎并且有 tables 其中有数亿个活动行,我会不太关心我如何查询缓存(由于您的复杂性较低,这是最有可能是最少的问题),但更多地关注数据库中数据的正确组织:

  • Prepared Statements 完全没问题。不要一遍又一遍地准备声明可能会有所帮助。相反,只需使用一组新的参数值重用现有的准备好的语句(某些环境甚至允许在客户端存储准备好的语句)。但是,这主要只是节省时间,用于查询缓存。由于您的查询的复杂性很低,可以假设这不会是最大的时间消耗者。
  • Key Caching (also called Key Buffering), however, is - as the name already suggests - key for your game! Most DB configurations of MySQL suffer greatly from wrong values in that area, as the buffers are way too small. In a nutshell, key caching makes sure that the references to the data (for instance in your indices) can be accessed in main memory. If they are not in memory, they need to be retrieved from the disk, which is slow. To see if your key cache is efficient, you should watch the key hit ratio, when your system is under load. Details about that is greatly explained at https://dba.stackexchange.com/questions/58182/tuning-key-reads-in-mysql
  • 如果缓存变大或由于使用其他 table 而频繁移动,为您的 table 创建自己的密钥缓存可能会有所帮助。详情见https://dev.mysql.com/doc/refman/5.5/en/cache-index.html
  • 如果您总是通过相同的属性访问 table 的大部分内容,那么使用 ALTER TABLE ... ORDER BY expr1, expr2, ... 更改磁盘上数据存储的顺序可能是有意义的。有关此方法的详细信息,另请参阅 https://dev.mysql.com/doc/refman/5.5/en/optimizing-queries-myisam.html
  • 避免使用可变长度列,例如 VARCHARBLOBTEXT。它们可能有助于节省一些 space,但尤其是比较它们的值会变得非常耗时。但是请注意,已经有一个此类类型的列将 MySQL 切换到 Dynamic 列模式。
  • 运行 ANALYZE TABLE 大量数据更改后保持统计数据最新。如果您删除了很大的区域,这可能有助于 OPTIMIZE TABLE,有助于确保在阅读时没有需要跳过的大空白。
  • 如果不需要回复,请使用INSERT DELAYED异步写入更改。如果在同一时间点周围还有其他 SELECT 语句,这将大大提高您的性能。
  • 或者,如果您需要回复,您可以使用 INSERT LOW_PRIORITY。那么与 INSERT 相比,并发 SELECT 的执行是首选。这可能有助于减轻一点痛苦,即 MyISAM 仅支持 table 级锁定。
  • 您可以尝试为您的查询提供 Index Hints,尤其是当您的 table 上有多个相互重叠的索引时。您应该尝试使用宽度最小但仍涵盖最多属性的索引。 但是,请注意,在您的情况下,影响必须非常小:您没有 ordering/grouping 或加入,因此查询优化器应该已经非常擅长找到最佳优化器。只需在您的 SELECT 语句中使用 EXPLAIN 来检查所用索引的选择是否合理。

总之,Prepared Statements完全可以。密钥缓存是关键 - 您还可以做一些其他事情来帮助 MySQL 处理大量数据。