我在InnoDB表中的列a VARCHAR(255), b INT
上有一个索引。给定两个a,b
对,我可以使用MySQL索引来确定c程序中的对是否相同(即不使用strcmp
和数字比较)?
注意:这个问题的答案应该是: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
这里的关键是我将字段a
和b
传递给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)
。
答案 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
州。)
您可以通过做两件事来访问索引而不触及表格
创建一个体面的覆盖指数
ALTER TABLE table
ADD INDEX abc_ndx(a,b,c,val);
运行我之前提到的SELECT
查询
由于查询的所有列都在索引中,因此查询优化器只会触摸索引(或预缓存索引页)。如果表格是MyISAM,你可以......
SELECT a,b,c,val FROM table;
将索引页加载到MyISAM的默认密钥缓存中相信我,你真的不想针对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.
来自您的上一条评论
我正在使用InnoDB,我可以看到MVCC模型如何使事情复杂化。但是,显然InnoDB只在索引中存储了一个版本(最新版本)。相关表的访问模式是一次写入,读取多次,因此如果可以访问索引,它可以为每个键提供单个可靠的数据。
说到InnoDB,MVCC并没有让任何事情变得复杂。它实际上可以成为你提供的最好的朋友:
如果重复读取,我希望所访问的索引页几乎永远位于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_size或max_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的程序(这是很多工作),
HandlerSocket:允许NoSQL访问InnoDB表,在UDF中运行。见a very informative blog post from the developer。 HandlerSocket的目标是提供一个暴露为网络守护程序的NoSQL接口,但您可以使用相同的技术(以及大部分相同的代码)来提供一些查询将使用MySQL的东西。
memcached InnoDB plugin。提供对InnoDB表的memcached样式访问。
HailDB:允许NoSQL访问InnoDB表,在Embedded InnoDB之上运行。见conference presentation。 编辑: HailDB可能无法与MySQL并行运行。
我相信其中任何一个都可以与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语句来完成你需要的东西。