Използване на SQLite Доставчикът ADO.Net трябва да постави GUID директно в клаузата Where на заявката без използване на параметър

Има ли все пак просто 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 да съответства на данните в колоната, т.е. заявката винаги връща нула. Разбирам, че 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