如何在没有MySQL客户端的情况下直接访问MySQL InnoDB索引值?

时间:2012-11-09 23:57:57

标签: mysql c indexing innodb

我在InnoDB表中的列a VARCHAR(255), b INT上有一个索引。给定两个a,b对,我可以使用MySQL索引来确定c程序中的对是否相同(即不使用strcmp和数字比较)?

  1. 存储在文件系统中的MySQL InnoDB索引在哪里?
  2. 可以从单独的程序中读取和使用吗?格式是什么?
  3. 如何使用索引来确定两个键是否相同?
  4. 注意:这个问题的答案应该是:a)提供访问MySQL索引的方法以完成此任务;或b)解释为什么不能以这种方式实际访问/使用MySQL索引。特定于平台的答案很好,我在使用Red Hat 5.8。


    以下是此问题的上一个版本,它提供了更多上下文,但似乎分散了实际问题的注意力。我知道在MySQL中有其他方法可以完成这个例子,我提供了两个。这不是关于优化的问题,而是分解出许多不同动态生成的查询中存在的复杂性。

    我可以使用带子组的子选择来完成我的查询,例如

    SELECT c, AVG(max_val)
    FROM (
        SELECT c, MAX(val) AS max_val
        FROM table
        GROUP BY a, b) AS t
    GROUP BY c
    

    但是我写了一个UDF,允许我用一个选择来做,例如

    SELECT b, MY_UDF(a, b, val)
    FROM table
    GROUP by c
    

    这里的关键是我将字段ab传递给UDF,我手动管理每个组中的a,b个子组。列a是一个varchar,因此这需要调用strncmp来检查匹配项,但速度相当快。

    但是,我有一个索引my_key (a ASC, b ASC)。而不是手动检查a和b上的匹配,我可以访问并使用MySQL索引吗?也就是说,我可以在my_key中获取给定行的索引值或c中的a,b对(在UDF内)吗?如果是这样,指数值是否会保证对于任何值a,b都是唯一的?

    我想调用MY_UDF(a, b, val),然后从UDF中查找c中的mysql索引值(a,b)

4 个答案:

答案 0 :(得分:6)

回顾原始查询

SELECT c, AVG(max_val)
FROM
(
    SELECT c, MAX(val) AS max_val
    FROM table
    GROUP BY a, b
) AS t
GROUP BY c;

首先应确保子选择通过运行

为您提供所需内容
SELECT c, MAX(val) AS max_val
FROM table
GROUP BY a, b;

如果子选择的结果正确,则运行完整查询。如果结果是正确的,那么您应该执行以下操作:

ALTER TABLE `table` ADD INDEX abc_ndx (a,b,c,val);

这将通过仅从索引获取所有需要的数据来加速查询。无需咨询源表。

编写UDF并将其称为单个SELECT只是伪装一个子选择并创建比查询需要更多的开销。只需在存储过程中放置​​完整查询(对数据进行一次嵌套传递)就可以更有效地获取UDF中的大部分数据并迭代地执行单行选择(类似于O(n log n)运行时间可能更长) Sending data州。)

更新2012-11-27 13:46 EDT

您可以通过做两件事来访问索引而不触及表格

  • 创建一个体面的覆盖指数

    ALTER TABLE table ADD INDEX abc_ndx(a,b,c,val);

  • 运行我之前提到的SELECT查询

由于查询的所有列都在索引中,因此查询优化器只会触摸索引(或预缓存索引页)。如果表格是MyISAM,你可以......

  1. 将MyISAM表设置为具有可在mysqld startup
  2. 上预加载的专用密钥缓存
  3. 运行SELECT a,b,c,val FROM table;将索引页加载到MyISAM的默认密钥缓存中
  4. 相信我,你真的不想针对mysqld的意愿访问索引页面。这是什么意思?

    对于MyISAM,MyISAM表的索引页存储在表的.MYI文件中。每个DML语句都会召唤一个完整的表锁。

    对于InnoDB,索引页面被加载到InnoDB缓冲池中。因此,关联的数据页面也将加载到InnoDB缓冲池中。

    由于MyISAM需要不断的I / O或InnoDB正在运行的常量MVCC协议,因此您不必使用Python,Perl,PHP,C ++或Java来规避对索引页的访问。

    有一个NoSQL范例(称为HandlerSocket)允许对MySQL表进行低级访问,可以干净地绕过mysqld的正常访问模式。 I would not recommend it since there was a bug in it when using it to issue writes.

    更新2012-11-30 12:11 EDT

    来自您的上一条评论

      

    我正在使用InnoDB,我可以看到MVCC模型如何使事情复杂化。但是,显然InnoDB只在索引中存储了一个版本(最新版本)。相关表的访问模式是一次写入,读取多次,因此如果可以访问索引,它可以为每个键提供单个可靠的数据。

    说到InnoDB,MVCC并没有让任何事情变得复杂。它实际上可以成为你提供的最好的朋友:

    • 如果您启用了autocommit(默认情况下应该启用)
    • 相关表的访问模式是一次写入,多次读取

    如果重复读取,我希望所访问的索引页几乎永远位于InnoDB缓冲池中。 I would just make sure your innodb_buffer_pool_size is set high enough to hold necessary InnoDB data

答案 1 :(得分:4)

您可能无法直接访问密钥。 我不认为这会在性能方面产生任何不同。

如果按正确的顺序设置覆盖率,MySQL将不会从硬盘中获取单个页面,而是直接将结果传递出索引。没有什么比这更快了。

请注意,如果子选择的结果大于tmp_table_sizemax_heap_table_size,则您的子选择可能最终会出现在磁盘上的temptable中。

如果您不确定,请检查Created_tmp_tables_disk_tables的状态。

有关MySQL如何使用您在此处找到的内部临时表的更多信息 http://dev.mysql.com/doc/refman/5.5/en/internal-temporary-tables.html

如果需要,请发布您的表格结构以供审核。

答案 2 :(得分:4)

如果只是想要访问MySQL之外的索引,则必须使用MySQL storage engines之一的API。默认引擎是InnoDB。请参阅此处的概述:InnoDB Internals。这描述了(在很高的层次上)磁盘上的数据布局和访问它的API。更详细的说明如下:Embedded InnoDB

但是,您可以使用其中一个已经完成这项工作的项目,而不是编写自己直接使用InnoDB API的程序(这是很多工作),

我相信其中任何一个都可以与MySQL并排运行(使用相同的表格),并且可以在C中使用,因此它们确实符合您的要求。

如果您可以使用/迁移到MySQL群集,另请参阅NDB API,一个直接API和ndbmemcache,这是一种使用memcache API访问MySQL群集的方法。

如果不知道为什么要这样做,这很难回答,因为不同方法的含义是截然不同的。

答案 3 :(得分:0)

没有。没有实际的方法可以在C程序中使用MySQL索引,以MySQL引擎以外的方式访问MySQL索引,以检查两个(a,b)对(密钥)是否相同

有更多实用的解决方案,不需要访问MySQL引擎之外的MySQL数据文件或编写用户定义的函数。


问:您知道mysql索引在文件系统中的存储位置吗?

文件系统中索引的位置将取决于表的存储引擎。对于MyISAM引擎,索引存储在datadir / database目录下的.MYI文件中; InnoDB索引存储在InnoDB托管表空间文件中。在创建表时设置了innodb_file_per_table变量,innodb_data_home_dir / database子目录下的每个表都会有一个单独的.ibd文件。

问:你知道格式是什么吗?

每个存储引擎的存储格式不同,MyISAM,InnoDB等,也取决于版本。根据MySQL对存储引擎的要求,我对数据的存储方式有一定的了解。有关内部结构的详细信息将特定于每个引擎。

问:是什么让它变得不切实际?

这是不切实际的,因为它涉及很多工作,而且它将依赖于未来可能会发生变化的存储引擎的细节。定义问题空间并编写一个可以返回所需内容的SQL语句会更加实用。

正如Quassnoi在对你的问题的评论中指出的那样,通过创建UDF或从MySQL外部访问MySQL索引,你想要解决的是什么特殊问题并不清楚。我确信Quassnoi有一个很好的方法来通过高效的SQL语句来完成你需要的东西。