Использование поставщика SQLite ADO.Net. Необходимо поместить GUID непосредственно в предложение запроса без использования параметра.

Есть ли способ, чтобы GUID был частью самого SQL-запроса без использования параметра?

Позвольте мне объяснить, что именно я пытаюсь сделать и почему. Я работаю с существующим приложением, которое использует ADO.Net для создания и подключения к базе данных SQLite. Нынешняя структура базы данных и метод запроса к ней ужасны. Я нахожусь в середине редизайна того, как это работает фундаментально. Однако это не то, что можно сделать быстро. Пока этот редизайн завершается, у меня возникла ситуация, требующая временного решения. Напомню, что причина первоначальной реализации кода неясна и, похоже, была создана кем-то, у кого было мало знаний о базах данных. Рефакторинг всей базы данных, чтобы не нуждаться в этой ситуации, является окончательным решением, но пока я просто ищу работу в рамках существующей структуры.

Дизайн базы данных основан на GUID для уникальной идентификации строк. Чтобы выполнить отфильтрованное извлечение данных, система динамически создает команду, содержащую предложение IN, в котором перечислены идентификаторы GUID, которые необходимо получить. Прямо сейчас идентификаторы GUID вставляются в запрос с помощью параметра с типом GUID, поэтому запрос будет выглядеть так:

SELECT * FROM data_table WHERE guid_col IN( ?, ?, ?, ?)

Проблема возникает, когда мне нужно получить относительно большой объем информации. SQLite имеет ограничение в 1000 параметров в одном запросе. Если мне нужно передать более 1000 GUID для поиска, запрос просто сломается. При построении приведенной выше строки она перебирает список GUID, чтобы вставить вопросительные знаки и создать параметры. Мое временное решение проблемы должно было заключаться в том, чтобы значение GUID было вставлено непосредственно туда, где в настоящее время находятся вопросительные знаки, и отказалось от параметров в запросе. В конце концов, это своего рода использование параметров для целей, для которых они не нужны.

Проблема с этим «решением» заключается в том, что я не могу заставить GUID соответствовать данным в столбце, т. е. запрос всегда возвращает значение null. Я понимаю, что идентификаторы GUID не являются родным типом для SQLite, и под ними они фактически представлены как BLOB (да, я уверен, что мы используем BLOB, а не строковое представление). Тем не менее, мне не удалось заставить запрос выполняться правильно.

До сих пор я пробовал все следующее:

Я попытался вызвать ToString() для GUID, поэтому запрос выглядит так:

SELECT * FROM data_table WHERE guid_col IN
   ( 'b5080d4e-37c3-4286-9c3a-413e8c367f36', 'aa0ff789-3ce9-4552-9840-5ed4d73c1e2c')

Я попытался вызвать ToString ("N") для GUID, поэтому запрос выглядит так:

SELECT * FROM data_table WHERE guid_col IN
  ( 'b5080d4e37c342869c3a413e8c367f36', 'aa0ff7893ce9455298405ed4d73c1e2c')

Я попытался вызвать ToString ("B") для GUID, поэтому запрос выглядит так:

SELECT * FROM data_table WHERE guid_col IN
  ( '{b5080d4e-37c3-4286-9c3a-413e8c367f36}',
    '{aa0ff789-3ce9-4552-9840-5ed4d73c1e2c}')

Я попытался вызвать ToByteArray() для GUID и поместить результат в запрос, добавив каждый байт в строку, вызывающую ToString("X") для каждого байта, чтобы запрос выглядел как

SELECT * FROM data_table WHERE guid_col IN ('4ED8B5C33786429C3A413E8C367F36', '89F7FAAE93C524598405ED4D73C1E2C')

При чтении документации SQLite я прочитал следующее: «BLOB-литералы — это строковые литералы, содержащие шестнадцатеричные данные, которым предшествует один символ «x» или «X». Если я попытаюсь применить это к моему запросу, это будет выглядеть так:

SELECT * FROM data_table WHERE guid_col IN
    ( x'4ED8B5C33786429C3A413E8C367F36', x'89F7FAAE93C524598405ED4D73C1E2C')

Я получаю сообщение об ошибке, говорящее, что «x» не является распознанным символом.

Можно ли получить GUID в строке запроса без использования параметра?


person Craig Suchanec    schedule 03.10.2011    source источник
comment
Более тысячи параметров к запросу??? МОЙ БОГ! Мне чрезвычайно трудно понять, какой разумный запрос должен достичь этого предела.   -  person Donal Fellows    schedule 01.12.2011
comment
Это не совсем разумный запрос или здравое мышление, которые привели его к существованию. Причина его существования в том, что это данные, сгенерированные для итеративного процесса, который может выполняться десятки тысяч раз. Каждая итерация вставляет новые строки. Затем пользователи могут ограничить, какие итерации возвращать, и делать это блоками. Я действительно не хочу, чтобы он использовал параметр, потому что на самом деле это просто оператор IN, конструируемый на лету. Есть и другие осложняющие факторы для всего этого. Мы находимся в процессе переподписания, чтобы избавиться от этих проблем, однако на данный момент мы как бы застряли с этим.   -  person Craig Suchanec    schedule 01.12.2011


Ответы (2)


Я предлагаю вам использовать временную таблицу для чего-то подобного. Например...

PRAGMA temp_store = MEMORY;

CREATE TEMP TABLE tbl_guids (guid_col text);

INSERT INTO tbl_guids VALUES ('b5080d4e-37c3-4286-9c3a-413e8c367f36');
INSERT INTO tbl_guids VALUES ('aa0ff789-3ce9-4552-9840-5ed4d73c1e2c');
... more inserts ...

SELECT * FROM data_table WHERE guid_col IN ( SELECT guid_col FROM tbl_guids);

DROP TABLE tbl_guids;

Обязательно оберните транзакцию вокруг всех операторов INSERT INTO. Это поможет с производительностью на тонну. Также SQLite позволяет временным таблицам полностью существовать в памяти, установив PRAGMA temp_store = MEMORY

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

person tidwall    schedule 30.11.2011
comment
Я думал, что временные таблицы SQLite были для каждого соединения? - person Donal Fellows; 01.12.2011
comment
Временные таблицы для каждого соединения. Пока соединения не объединяются и не используются ADO.net, вы должны быть в безопасности и не нуждаться в уникальных случайных числах. - person tidwall; 01.12.2011
comment
Интересная мысль. К базе данных одновременно подключается только один пользователь, поэтому уникальность не является проблемой. Вы хоть представляете, какие характеристики производительности можно сравнить с прямым запросом? Кажется, что это может быть очень медленно. Я должен изучить это. - person Craig Suchanec; 01.12.2011
comment
Зависит от количества строк и скорости диска. Пока у вас есть BEGIN TRANSACTION и END TRANSACTION вокруг вставок, вы должны увидеть очень хорошую производительность записи. Чтобы еще больше ускорить запись и чтение, запустите PRAGMA temp_store=MEMORY. - person tidwall; 01.12.2011

Вы можете передавать GUID в виде строк, если вы установите «BinaryGuid=False» в строке подключения. Если это сделано, "ToString()" должен работать нормально.

person oillio    schedule 30.05.2012