|
Запрос с множественными комбинациями в условии
|
|||
---|---|---|---|
#18+
Здравствуйте всем! IBM DB2 WSE 9.7 В базе есть таблицы: 1. REGISTER (IDREG as bigint, IDNSI1 as bigint, IDNSI2 as bigint, IDNSI3 as bigint, IDNSI4 as bigint, IDNSI5 as bigint, IDNSI6 as bigint, IDNSI7 as bigint и другие) 2. NSI1 (IDNSI1 as bigint, NAM1 as varchar(100)) 3. NSI2 (IDNSI2 as bigint, NAM2 as varchar(100)) 4. NSI3 (IDNSI3 as bigint, NAM3 as varchar(100)) 5. NSI4 (IDNSI4 as bigint, NAM4 as varchar(100)) 6. NSI5 (IDNSI5 as bigint, NAM5 as varchar(100)) 7. NSI6 (IDNSI6 as bigint, NAM6 as varchar(100)) 8. NSI7 (IDNSI7 as bigint, NAM7 as varchar(100)) Необходимо подсчитать количество записей из REGISTER, например в 3 колонки, где для каждой из колонок заданы определенные условия NAM из разных NSI. Например, вычислить количество P1, P2, P3, где в P1 должны подсчитываться записи с комбинациями (NAM1, NAM2, NAM4)=('1VAL1', '1VAL2',' 1VAL4') и (NAM1, NAM5, NAM6, NAM7)=('2VAL1', '2VAL5',' '2VAL6','2VAL7') и (NAM3, NAM4, NAM5)=('3VAL3', '3VAL4',' 3VAL5') и другие, в P2 должны подсчитываться записи с комбинациями (NAM1, NAM2, NAM4, NAM7)=('1VAL1', '1VAL2',' 1VAL4','1VAL7') и (NAM1, NAM5, NAM6)=('2VAL1', '2VAL5', '2VAL6') и (NAM3, NAM4, NAM5, NAM6)=('3VAL3', '3VAL4',' 3VAL5', '3VAL6') и другие, в P3 - еще один набор комбинации и т.д. Мне, кроме как применять конструкции case when, больше не видится как реализовать это запрос. Но в этом случае запрос становится громадным и наверно не оптимальным. Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.
Подскажите, может есть более красивый и оптимальный способ? С уважением, Семен Попов ... |
|||
:
Нравится:
Не нравится:
|
|||
30.09.2016, 16:27 |
|
Запрос с множественными комбинациями в условии
|
|||
---|---|---|---|
#18+
Есть идея. Все возможные комбинации условий запихнуть во временную таблицу CONDITIONS (IDCON, IDNSI1, IDNSI2, IDNSI3, IDNSI4, IDNSI5, IDNSI6, IDNSI7). В тех полях, что допускают любые значения, внести значение 0 или null. А затем как-то ее наложить на REGISTER. Возможно, написать пользовательскую функцию ISCOND (CONNUM), которая бы сверяла вхождения CONDITIONS в записи REGISTER и возвращала значение 0 или 1. Временная таблица с ID еще хороша тем, что при подсчете сверяются числовые значения. Работа с числами всегда быстрее, чем со строками. Тогда запрос превратился бы в нечто иное Код: plsql 1. 2.
Скажите, правильно ли я мыслю? ... |
|||
:
Нравится:
Не нравится:
|
|||
03.10.2016, 12:10 |
|
Запрос с множественными комбинациями в условии
|
|||
---|---|---|---|
#18+
Semen Popov... Тогда запрос превратился бы в нечто иное Код: plsql 1. 2.
Нет. Запрос будет выглядеть так Код: plsql 1. 2.
... |
|||
:
Нравится:
Не нравится:
|
|||
03.10.2016, 16:10 |
|
Запрос с множественными комбинациями в условии
|
|||
---|---|---|---|
#18+
Semen Popov, Оптимальность не бывает "подвешена в воздухе". - Каковы вообще предполагаемые объёмы данных? Тысячи строк, миллионы, сотни миллионов, больше? Может вообще овчинка выделки не стоит и как ни делай, всё равно. - Каковы относительные объёмы? Можно предположить, что таблицы NISx - "справочники" с относительно малым объёмом (единицы строк, тысячи, десятки, миллионы), а вот "REGISTER" - таблица фактов несравнимо большего объёма. - Являются ли bigint значения в таблицах NISx первичными ключами ключами? Уникальны ли NAMx в рамках своих таблиц? - Являются приведённые запросы - "профильной" нагрузкой? Т.е. надо ли строить всё преимущественно под них. - Есть ли наиболее часто используемые группы в наборах (NAMx, NAMy, NAMz, ...) или это под какую-нибудь аналитику/дата-майнинг, прости господи, чтобы данные со всех сторон вертеть? (Они в имеющихся решениях чаще вертятся уже полностью выгруженные на клиент) - Как обновляются таблицы? Далее в предположении, что данных много. Приведённые Вами способы выразить запрос приведут к полному построению ("развёртыванию") имеющейся конструкции (этакая денормализация в одну таблицу). Второй способ не до конца ясен, пока Вы не привели код ISCOND(x) ф-и, но ситуфция, полагаю, будет схожей. СУБД не настолько "умна", чтобы развернуть логику внутри SUM, чтобы исключить из построения часть строк ("понимая", что 0 не повлияет на сумму, да и вообще как-то соображая, как тот 0 может получиться). Ситуация подобна выборке по предикату "where F(column_X) = ?". Сколько ни строй индексов по column_X, потребуется просканировать всю таблицу, построить все результаты и произвести сравнение. Ровно потому, что в общем случае (если Вы сталкивались с теорией алгоритмов) машинным образом построить обратный алгоритм и преобразовать предикат в "where column_X = F1(?)" невозможно (и не всегда такая обратная ф-я вообще есть). /* Может быть не совсем так с INLINED SQL ф-ей, и есть костыль в виде функционального индекса */ Давайте теперь посмотрим, что будет происходить. Это будет full scan по самой большой таблице (REGISTER?) с допустим миллионом записей с последующим объединением с NISx с пусть хотя бы по 1000 записей. Так или иначе объединяя записи (просто проверяя условие объединения) потребуется перелопатить: 1000000*1000*1000*1000*1000*1000*1000*1000 строк, оставить тот же 1000000 и физически сформировать гораздо более широкую со строками вместо bigint, потом пройтись этому 1000000 строк для вычисления окончательного результата. Это будет долго. Очень долго. Вообще говоря, приведённая структура таблиц более менее стандартна для хранилищ (если верно предположение о характере и относительных объёмах таблиц). СУБД хорошо с ними работают. Только пишите более понятно для оптимизатора (предполагая, что NAMx уникальны в NSIx): Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19.
Или вообще выполняйте эти запросы по отдельности. Все запросы к NISx выродятся в несколько коротких look-up'ов, далее зависит от индексов на REGISTER. В худшем случае просто full-scan таблицы. В лучшем - INDEX scan(s) и динамическое построение bitmap index'а или просто scan по региону индекса. Можете оставить: Код: sql 1. 2. 3. 4. 5. 6.
Оптимизатор развернёт эту констркцию как надо (но всё-таки всегда проверяйте получившийся план). Только пожалуйста, используйте в данном случае просто join, чтобы как раз отфильтровать записи из REGISTER и выбросите лишние, чтобы отбросить ненужную фильтрацию по наличию записей в неиспользуемых в предикате "таблиц-справочников". В качестве упражнения - оформить несколько запросов в виде Common Table Expression (CTE) и собрать результат в одну строку ;) Как мне представляется - неверный посыл с Вашей стороны - попытка оформить всё в таком виде, чтобы при выполнении осущесвлялся только один проход по таблице. PS Если данных _действительно_ много, то есть ещё такая вещь, как BLU Acceleration (но не в 9.7). В общем, вам действительно надо или абстрактный интерес? ... |
|||
:
Нравится:
Не нравится:
|
|||
04.10.2016, 19:29 |
|
Запрос с множественными комбинациями в условии
|
|||
---|---|---|---|
#18+
CawaSPb, спасибо за развернутые пояснения. Попробую ответить на Ваши вопросы. 1. количество записей в REGISTER - ~ 1,6 млн. Но в таблице присутствует поле DATREG (дата регистрации), и в отчет будут задаваться дополнительные условия ограничения по этой дате (период с и по). Поэтому в итоге подсчет будет выполняться по меньшему количеству записей - ~500-600 тыс. 2. количество справочников (NSI) не 7, а 8. Но это наверно сути не меняет. Число записей в них разное, от 100 до 500. NAM внутри одного справочника может повторяться. Ограничений на уникальность NAM не накладывается. Наложена уникальность только по IDNSI (первичный ключ). 3. разрабатываемый запрос не является "профильной загрузкой". Обращение к этим цифрам будет непостоянное. Раз в неделю или вообще раз в месяц. 4. Обновление NSI происходит редко. В таблицу REGISTER в основном происходит вставка записей (ежедневно до 1000). Изменение записей редко. 5. В условиях можно выделить пересечение в комбинациях, но только в пределах подсчета одного показателя. Например, для P1 должны подсчитываться записи с комбинациями (NAM3, NAM4, NAM5)=('3VAL1', '4VAL1',' 5VAL1') и (NAM3, NAM4, NAM5, NAM6)=('3VAL1', '4VAL2',' '5VAL2','6VAL1') и (NAM3, NAM4, NAM5)=('3VAL1', '4VAL3',' 5VAL3') В P2 и P3 тоже можно найти пересечения только внутри показателя. В целом предполагаю, что тут в любом случае будет полный скан таблицы. И реализация будет сводится к тому, чтобы сократить предварительное количество записей, например для P1 условие where (D1<=DATREG and DATREG<=D2) and NAM3='3VAL1' , а подсчет уже проводить по полученному массиву. Но в этом случае придется для каждого показателя свои условия where. То есть вообще разбить на несколько под запросов по одной и той же таблице. Ну и подумать над алгоритмом поиска записи по подходящим параметрам, чтобы тот был максимально производительным. Про функцию я говорил и вижу примерный результат: Как-то так Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119.
... |
|||
:
Нравится:
Не нравится:
|
|||
05.10.2016, 11:37 |
|
Запрос с множественными комбинациями в условии
|
|||
---|---|---|---|
#18+
Как оказалось, скрипт ниже работает быстрее, чем тот, что я предложил выше (через функцию) Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40.
... |
|||
:
Нравится:
Не нравится:
|
|||
18.10.2016, 11:38 |
|
|
start [/forum/topic.php?fid=43&fpage=12&tid=1600525]: |
0ms |
get settings: |
10ms |
get forum list: |
13ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
47ms |
get topic data: |
12ms |
get forum data: |
3ms |
get page messages: |
46ms |
get tp. blocked users: |
2ms |
others: | 300ms |
total: | 441ms |
0 / 0 |