Как я могу напрямую получить доступ к индексам MySQL InnoDB без клиента MySQL?

У меня есть индекс в столбцах a VARCHAR(255), b INT в таблице InnoDB. Учитывая две пары a,b, могу ли я использовать индекс MySQL для определения того, являются ли пары одинаковыми из программы c (т.е. Без использования strcmp и численного сравнения)?

  • Где индекс MySQL InnoDB, хранящийся в файловой системе?
  • Можно ли его читать и использовать из отдельной программы? Каков формат?
  • Как я могу использовать индекс для определения того, являются ли два ключа одинаковыми?

Примечание. Ответ на этот вопрос должен либо 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 для данной строки или пары a,b в c (внутри UDF)? И если да, гарантировано ли значение индекса уникальным для любого значения a,b?

Я хотел бы вызвать MY_UDF(a, b, val), а затем посмотреть значение индекса mysql (a,b) в c из UDF.

Ответ 1

Если вы просто хотите получить доступ к индексу вне MySQL, вам придется использовать API для одного из устройств хранения MySQL. Двигатель по умолчанию - InnoDB. См. Обзор здесь: Внутренние внутри InnoDB. Это описывает (на очень высоком уровне) как расположение данных на диске, так и API для доступа к нему. Более подробное описание здесь: Embedded InnoDB.

Однако вместо написания вашей собственной программы, которая напрямую использует API-интерфейс InnoDB (что очень много), вы можете использовать один из проектов, которые уже сделали эту работу:

  • HandlerSocket: предоставляет NoSQL доступ к таблицам InnoDB, работает в UDF. Смотрите очень информативное сообщение в блоге от разработчика. Цель HandlerSocket - предоставить интерфейс NoSQL, открытый в качестве сетевого демона, но вы можете использовать ту же технику (и большую часть того же кода), чтобы предоставить что-то, что будет использоваться в запросе с MySQL.

  • memcached плагин InnoDB. предоставляет доступ к файлу memcached для таблиц InnoDB.

  • HailDB: предоставляет NoSQL доступ к таблицам InnoDB, работает поверх Embedded InnoDB. см. презентация конференции. EDIT: HailDB, вероятно, не будет работать одновременно с MySQL.

Я считаю, что любой из них может работать бок о бок с MySQL (используя одни и те же таблицы в прямом эфире) и может использоваться с C, чтобы они соответствовали вашим требованиям.

Если вы можете использовать/перенести в MySQL Cluster, см. также NDB API, прямой API и ndbmemcache, способ доступа к кластеру MySQL с помощью API memcache.

Трудно ответить, не зная, почему вы пытаетесь это сделать, потому что последствия разных подходов очень разные.

Ответ 2

Посмотрите на свой исходный запрос

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, вы можете...

  • настройте таблицу MyISAM, чтобы иметь выделенный кеш-ключ, который можно предварительно загрузить при запуске mysqld
  • запустите SELECT a,b,c,val FROM table;, чтобы загрузить страницы индексирования в ключевой кэш MyISAM

Поверьте мне, вы действительно не хотите получать доступ к страницам индексов против mysqld. Что я имею в виду?

Для MyISAM страницы индекса для таблицы MyISAM хранятся в файле .MYI таблицы. Каждый оператор DML вызовет полную блокировку таблицы.

Для InnoDB страницы индекса загружаются в пул буферов InnoDB. Следовательно, связанные страницы данных будут загружаться в пул буферов InnoDB, а также.

Вам не нужно обойти доступ к страницам индекса с использованием Python, Perl, PHP, С++ или Java из-за постоянного ввода-вывода, необходимого MyISAM или константе MVCC, осуществляемый InnoDB.

Существует парадигма NoSQL (называемая HandlerSocket), которая позволила бы низкоуровневому доступу к таблицам MySQL, которые могли бы чисто обходить обычные шаблоны доступа mysqld. Я бы не рекомендовал его, так как в нем была ошибка при использовании для публикации.

ОБНОВЛЕНИЕ 2012-11-30 12:11 EDT

Из вашего последнего комментария

Я использую InnoDB, и я вижу, как модель MVCC усложняет ситуацию. Однако, по-видимому, InnoDB хранит только одну версию (самую последнюю) в индексе. Шаблон доступа для соответствующих таблиц - это write-once, read-many, поэтому, если доступ к индексу можно получить, он может обеспечить единую, надежную привязку для каждого ключа.

Когда дело доходит до InnoDB, MVCC ничего не усложняет. Это может стать вашим лучшим другом при условии:

  • если вы включили autocommit (по умолчанию он должен быть включен)
  • шаблон доступа для соответствующих таблиц - однократный, read-many

Я ожидал бы, что доступные страницы индекса будут сидеть в пуле буферов InnoDB практически навсегда, если он будет читаться повторно. Я бы просто удостоверился, что ваш innodb_buffer_pool_size установлен достаточно высоко, чтобы хранить необходимые данные InnoDB.

Ответ 3

Вероятно, вы не можете напрямую обращаться к ключу. Я не думаю, что это действительно повлияло бы на производительность.

Если вы установите накрывающие индексы в правильном порядке, MySQL не будет извлекать одну страницу с жесткого диска, а выводить результат непосредственно из индекса. Там ничего быстрее, чем это.

Обратите внимание, что ваш подзаголовок может оказаться на соблазнительном диске, если его результат будет больше, чем ваш tmp_table_size или max_heap_table_size.

Проверьте состояние Created_tmp_tables_disk_tables, если вы не уверены.

Подробнее о том, как MySQL использует внутренние временные таблицы, вы найдете здесь http://dev.mysql.com/doc/refman/5.5/en/internal-temporary-tables.html

Если вы хотите, опубликуйте свою структуру таблицы для просмотра.

Ответ 4

Нет. Практически невозможно использовать индекс MySQL изнутри программы C, обращаясь к индексу MySQL, не зависящим от механизма MySQL, для проверки того, являются ли две (a, b) пары (ключи) одинаковыми или нет.

Есть более практичные решения, которые не требуют доступа к файлам данных MySQL за пределами механизма MySQL или записи пользовательской функции.


Q: Знаете ли вы, где индекс mysql хранится в файловой системе?

Местоположение индекса в файловой системе будет зависеть от механизма хранения для таблицы. Для движка MyISAM индексы хранятся в файлах .MYI в каталоге datadir/database; Индексы InnoDB хранятся в файле управляемых табличных пространств InnoDB. f innodb_file_per_table была задана при создании таблицы, будет отдельный файл .ibd для каждой таблицы в подкаталоге innodb_data_home_dir/database.

Q: Знаете ли вы, что такое формат?

Формат хранения для каждого механизма хранения отличается от MyISAM, InnoDB и др., а также зависит от версии. У меня есть некоторое знакомство с тем, как хранятся данные, с точки зрения того, что MySQL требует от механизма хранения. Подробная информация о внутренних деталях будет специфичной для каждого двигателя.

Q: Что делает его непрактичным?

Это непрактично, потому что это целая работа, и это будет зависеть от деталей движков хранения, которые могут измениться в будущем. Было бы гораздо более практичным определить проблемное пространство и написать инструкцию SQL, которая вернет то, что вы хотите.

Как указал Кваснуй в своем комментарии к вашему вопросу, он совершенно не понимает, какую конкретную проблему вы пытаетесь решить, создав UDF или получив доступ к индексам MySQL извне MySQL. Я уверен, что Quassnoi будет иметь хороший способ выполнить то, что вам нужно, с помощью эффективного оператора SQL.