Поиск повторяющихся идентификаторов
Материал из GedeminWiki
(Различия между версиями)
SYSDBA (обсуждение | вклад) (Новая страница: «Идеология платформы Гедымин требует уникальности идентификаторов объектов в пределах фа…») |
SYSDBA (обсуждение | вклад) |
||
| (не показаны 3 промежуточные версии 1 участника) | |||
| Строка 1: | Строка 1: | ||
Идеология платформы Гедымин требует уникальности идентификаторов объектов в пределах файла базы данных. Дублирующиеся идентификаторы являются следствием физического повреждения базы данных или логических сбоев в программном обеспечении. | Идеология платформы Гедымин требует уникальности идентификаторов объектов в пределах файла базы данных. Дублирующиеся идентификаторы являются следствием физического повреждения базы данных или логических сбоев в программном обеспечении. | ||
| + | |||
| + | ===Поиск дубликатов с использованием временной таблицы=== | ||
Для поиска дубликатов создадим временную таблицу TEMP: | Для поиска дубликатов создадим временную таблицу TEMP: | ||
| Строка 63: | Строка 65: | ||
count(t.id) > 1 | count(t.id) > 1 | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| + | |||
| + | ===Поиск дубликатов с использованием битовых массивов=== | ||
| + | |||
| + | На сервере должна быть установлена библиотека GUDF.DLL. Используются два битовых массива. База данных сканируется дважды. На первом проходе, первый массив заполняется всеми ИД из БД, второй -- только повторяющимися. На втором проходе выводится список повторяющихся ИД с именами таблиц. | ||
| + | |||
| + | <syntaxhighlight lang="SQL"> | ||
| + | EXECUTE BLOCK | ||
| + | RETURNS(ID INTEGER, RN CHAR(31)) | ||
| + | AS | ||
| + | DECLARE VARIABLE DUMB INTEGER; | ||
| + | BEGIN | ||
| + | g_his_create(0, 0); | ||
| + | g_his_create(1, 0); | ||
| + | |||
| + | FOR | ||
| + | SELECT DISTINCT | ||
| + | r.rdb$relation_name | ||
| + | FROM | ||
| + | rdb$relation_fields rf JOIN rdb$relations r | ||
| + | ON r.rdb$relation_name = rf.rdb$relation_name | ||
| + | LEFT JOIN | ||
| + | ( | ||
| + | SELECT relc.rdb$relation_name | ||
| + | FROM | ||
| + | rdb$relation_constraints relc JOIN rdb$ref_constraints refc | ||
| + | ON refc.rdb$constraint_name = relc.rdb$constraint_name | ||
| + | JOIN rdb$index_segments iseg | ||
| + | ON iseg.rdb$index_name = relc.rdb$index_name | ||
| + | AND iseg.rdb$field_name = 'ID' | ||
| + | ) constr ON constr.rdb$relation_name = r.rdb$relation_name | ||
| + | WHERE | ||
| + | rf.rdb$field_name = 'ID' AND r.rdb$relation_name <> 'TEMP' | ||
| + | AND r.rdb$relation_name <> 'GD_RUID' | ||
| + | AND r.rdb$view_source IS NULL | ||
| + | AND constr.rdb$relation_name IS NULL | ||
| + | INTO :RN | ||
| + | DO BEGIN | ||
| + | EXECUTE STATEMENT | ||
| + | 'SELECT SUM(g_his_include(1, id)) ' || | ||
| + | ' FROM ' || :RN || | ||
| + | ' WHERE g_his_has(0, id) <> 0 ' | ||
| + | INTO :DUMB; | ||
| + | |||
| + | EXECUTE STATEMENT | ||
| + | 'SELECT SUM(g_his_include(0, id)) ' || | ||
| + | ' FROM ' || :RN | ||
| + | INTO :DUMB; | ||
| + | END | ||
| + | |||
| + | FOR | ||
| + | SELECT DISTINCT | ||
| + | r.rdb$relation_name | ||
| + | FROM | ||
| + | rdb$relation_fields rf JOIN rdb$relations r | ||
| + | ON r.rdb$relation_name = rf.rdb$relation_name | ||
| + | LEFT JOIN | ||
| + | ( | ||
| + | SELECT relc.rdb$relation_name | ||
| + | FROM | ||
| + | rdb$relation_constraints relc JOIN rdb$ref_constraints refc | ||
| + | ON refc.rdb$constraint_name = relc.rdb$constraint_name | ||
| + | JOIN rdb$index_segments iseg | ||
| + | ON iseg.rdb$index_name = relc.rdb$index_name | ||
| + | AND iseg.rdb$field_name = 'ID' | ||
| + | ) constr ON constr.rdb$relation_name = r.rdb$relation_name | ||
| + | WHERE | ||
| + | rf.rdb$field_name = 'ID' AND r.rdb$relation_name <> 'TEMP' | ||
| + | AND r.rdb$relation_name <> 'GD_RUID' | ||
| + | AND r.rdb$view_source IS NULL | ||
| + | AND constr.rdb$relation_name IS NULL | ||
| + | INTO :RN | ||
| + | DO BEGIN | ||
| + | FOR | ||
| + | EXECUTE STATEMENT | ||
| + | 'SELECT id ' || | ||
| + | ' FROM ' || :RN || | ||
| + | ' WHERE g_his_has(1, id) <> 0 ' | ||
| + | INTO :id | ||
| + | DO BEGIN | ||
| + | SUSPEND; | ||
| + | END | ||
| + | END | ||
| + | |||
| + | g_his_destroy(0); | ||
| + | g_his_destroy(1); | ||
| + | END | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | ====См. также==== | ||
| + | |||
| + | * [[ID і RUID]] | ||
[[Category:Школа системного администратора]] | [[Category:Школа системного администратора]] | ||
Текущая версия на 20:42, 24 июля 2014
Идеология платформы Гедымин требует уникальности идентификаторов объектов в пределах файла базы данных. Дублирующиеся идентификаторы являются следствием физического повреждения базы данных или логических сбоев в программном обеспечении.
[править] Поиск дубликатов с использованием временной таблицы
Для поиска дубликатов создадим временную таблицу TEMP:
CREATE TABLE temp ( id dintkey, relid dintkey )
Заполним ее:
EXECUTE BLOCK AS DECLARE VARIABLE RN CHAR(31); DECLARE VARIABLE RID INTEGER; BEGIN FOR SELECT DISTINCT r.rdb$relation_name, r.rdb$relation_id FROM rdb$relation_fields rf JOIN rdb$relations r ON r.rdb$relation_name = rf.rdb$relation_name LEFT JOIN ( SELECT relc.rdb$relation_name FROM rdb$relation_constraints relc JOIN rdb$ref_constraints refc ON refc.rdb$constraint_name = relc.rdb$constraint_name JOIN rdb$index_segments iseg ON iseg.rdb$index_name = relc.rdb$index_name AND iseg.rdb$field_name = 'ID' ) constr ON constr.rdb$relation_name = r.rdb$relation_name WHERE rf.rdb$field_name = 'ID' AND r.rdb$relation_name <> 'TEMP' AND r.rdb$relation_name <> 'GD_RUID' AND r.rdb$view_source IS NULL AND constr.rdb$relation_name IS NULL INTO :RN, :RID DO BEGIN EXECUTE STATEMENT 'INSERT INTO TEMP (id, relid) ' || ' SELECT id, ' || :RID || ' FROM ' || :RN || ' WHERE id > 32 ' WITH AUTONOMOUS TRANSACTION; END END
Теперь, получить список ИД, встречающихся более одного раза можно так:
SELECT t.id, COUNT(t.id), list(TRIM(r.rdb$relation_name)) FROM temp t JOIN rdb$relations r ON t.relid = r.rdb$relation_id GROUP BY t.id HAVING COUNT(t.id) > 1
[править] Поиск дубликатов с использованием битовых массивов
На сервере должна быть установлена библиотека GUDF.DLL. Используются два битовых массива. База данных сканируется дважды. На первом проходе, первый массив заполняется всеми ИД из БД, второй -- только повторяющимися. На втором проходе выводится список повторяющихся ИД с именами таблиц.
EXECUTE BLOCK RETURNS(ID INTEGER, RN CHAR(31)) AS DECLARE VARIABLE DUMB INTEGER; BEGIN g_his_create(0, 0); g_his_create(1, 0); FOR SELECT DISTINCT r.rdb$relation_name FROM rdb$relation_fields rf JOIN rdb$relations r ON r.rdb$relation_name = rf.rdb$relation_name LEFT JOIN ( SELECT relc.rdb$relation_name FROM rdb$relation_constraints relc JOIN rdb$ref_constraints refc ON refc.rdb$constraint_name = relc.rdb$constraint_name JOIN rdb$index_segments iseg ON iseg.rdb$index_name = relc.rdb$index_name AND iseg.rdb$field_name = 'ID' ) constr ON constr.rdb$relation_name = r.rdb$relation_name WHERE rf.rdb$field_name = 'ID' AND r.rdb$relation_name <> 'TEMP' AND r.rdb$relation_name <> 'GD_RUID' AND r.rdb$view_source IS NULL AND constr.rdb$relation_name IS NULL INTO :RN DO BEGIN EXECUTE STATEMENT 'SELECT SUM(g_his_include(1, id)) ' || ' FROM ' || :RN || ' WHERE g_his_has(0, id) <> 0 ' INTO :DUMB; EXECUTE STATEMENT 'SELECT SUM(g_his_include(0, id)) ' || ' FROM ' || :RN INTO :DUMB; END FOR SELECT DISTINCT r.rdb$relation_name FROM rdb$relation_fields rf JOIN rdb$relations r ON r.rdb$relation_name = rf.rdb$relation_name LEFT JOIN ( SELECT relc.rdb$relation_name FROM rdb$relation_constraints relc JOIN rdb$ref_constraints refc ON refc.rdb$constraint_name = relc.rdb$constraint_name JOIN rdb$index_segments iseg ON iseg.rdb$index_name = relc.rdb$index_name AND iseg.rdb$field_name = 'ID' ) constr ON constr.rdb$relation_name = r.rdb$relation_name WHERE rf.rdb$field_name = 'ID' AND r.rdb$relation_name <> 'TEMP' AND r.rdb$relation_name <> 'GD_RUID' AND r.rdb$view_source IS NULL AND constr.rdb$relation_name IS NULL INTO :RN DO BEGIN FOR EXECUTE STATEMENT 'SELECT id ' || ' FROM ' || :RN || ' WHERE g_his_has(1, id) <> 0 ' INTO :id DO BEGIN SUSPEND; END END g_his_destroy(0); g_his_destroy(1); END