|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
Задавал такой вопрос в форуме PostgreSQL. Там ответили что такой возможности там нет, но учитывая что там и predicate push down нет, а система кроссплатформенна возник принципиальный вопрос есть ли такая возможность в других СУБД. Ссылка на тот форум] http://www.sql.ru/forum/actualthread.aspx?tid=924906 Код: 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.
Такие запросы нужны для динамических списков с сортировкой по связанному полю. План выполнения : Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.
То есть join'им таблицы, сортируем, находим верхние 50 и фиг с ними с индексами. В итоге считывается вся база. Соответственно есть СУБД, которые догадываются бежать по B_x, для каждой записи бежать по A_b, выкидывая в результат соответствующие записи пока не наберется 50 записей? То есть фиг с ним бы с predicate push down, его можно обойти самому проталкивая контекст внутрь (что даже эффективнее иногда использования эвристик СУБД), а вот перестроить запрос с LIMIT'ом не понятно как :( Точнее можно но это будет такая трехэтажная конструкция, что проще действительно materialize'ить. ... |
|||
:
Нравится:
Не нравится:
|
|||
10.03.2012, 09:38 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
Bond_JamesBond, во первых объем данных слишком мал, любой нормальный оптимизатор примет решение вычитать фулсканом таблицы, т.к. это на таком объеме дешевле (пара многоблочных чтений). если увеличить размер то оракл, например, думаю и сам нестед луп применит. даже если не применит его оптимизатор всегда можно запинать хинтами и заставить применить нестед луп. ... |
|||
:
Нравится:
Не нравится:
|
|||
10.03.2012, 13:55 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
Во-первых какая у тебя версия PG и спроси в постгресовой ветке она уже поддерживает IOS? Во-вторых о чем уже сказал йошка - слишком малый объем данных чтобы делать NLJ. В-третьих если все таки поддержка IOS у тебя есть и хочешь использовать индексы для JOIN, то создай индекс Код: plsql 1. 2. 3. 4.
В-четвёртых расскажи, где у тебя в запросе предикаты, которые надо "predicate push down". И в-пятых расшифруй "Соответственно есть СУБД, которые догадываются бежать по B_x, для каждой записи бежать по A_b, выкидывая в результат соответствующие записи пока не наберется 50 записей?" ... |
|||
:
Нравится:
Не нравится:
|
|||
10.03.2012, 16:21 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
CREATE INDEX, Специально увеличил объем до 1 миллиона записей в А и 10к в В, принципиально ничего не поменялось : "Limit (cost=72845.26..72845.38 rows=50 width=16) (actual time=752.861..752.866 rows=50 loops=1)" " -> Sort (cost=72845.26..75341.27 rows=998403 width=16) (actual time=752.858..752.861 rows=50 loops=1)" " Sort Key: b.x, a.key0" " Sort Method: top-N heapsort Memory: 20kB" " -> Hash Join (cost=270.00..39679.03 rows=998403 width=16) (actual time=2.730..566.940 rows=1000000 loops=1)" " Hash Cond: (a.b = b.key0)" " -> Seq Scan on a (cost=0.00..14425.00 rows=1000000 width=8) (actual time=0.035..128.657 rows=1000000 loops=1)" " -> Hash (cost=145.00..145.00 rows=10000 width=8) (actual time=2.684..2.684 rows=10000 loops=1)" " Buckets: 1024 Batches: 1 Memory Usage: 313kB" " -> Seq Scan on b (cost=0.00..145.00 rows=10000 width=8) (actual time=0.006..1.064 rows=10000 loops=1)" "Total runtime: 752.969 ms" Версия СУБД: "PostgreSQL 9.1rc1, compiled by Visual C++ build 1500, 32-bit" Также на 9.0 проверено, очень сомневаюсь что в минор релизе добавили index only scan, да и не совсем понимаю причем он тут. Также не совсем понимаю чем ей поможет индекс по key0, x когда она знает что key0 primary key и для него ровно один x. Predicate push down привел для примера фичи, которую не поддерживает postgre, но поддерживают другие СУБД. Возможно здесь аналогичный случай. Если бы я писал вручную этот запрос то я бы грубо говоря сделал так : (привожу в синтаксисе "файл-серверной" СУБД например Foxpro, надеюсь будет понятно) SET INDEX TO B_x IN B SET INDEX TO A_b IN A SELECT B i=0 SCAN ALL SELECT A SET KEY TO B.key0 SCAN ALL i=i+1 MESSAGEBOX(A.key0) // вывод результата IF i>50 // RETURN ENDIF ENDSCAN SELECT B ENDSCAN Соответственно такой подход сделал бы все максимум за 50 итераций а не за 1 миллион как в моем случае ... |
|||
:
Нравится:
Не нравится:
|
|||
10.03.2012, 23:11 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
С табуляциями : Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.
Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16.
... |
|||
:
Нравится:
Не нравится:
|
|||
10.03.2012, 23:13 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
Второй индекс для SMJ. У тебя соединение по одним столбцам, один из которых не уникальный, сортировка по другим, первый из которых не уникальный. А так какой план будет? (обе таблицы увеличил в 100 раз, добавил индекс, и правое соединение) Код: 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.
... |
|||
:
Нравится:
Не нравится:
|
|||
10.03.2012, 23:24 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
CREATE INDEX, Да в общем то такой же Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.
... |
|||
:
Нравится:
Не нравится:
|
|||
11.03.2012, 00:26 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
Bond_JamesBond, Жесть. Установил Oracle 11g, он даже случай SELECT * FROM (SELECT * FROM A JOIN B ON B.key0=A.b ORDER BY B.x, B.key0) t0 WHERE rownum < 50; не разбирает. Хотя может я что-то не так делаю, буду еще разбираться... ... |
|||
:
Нравится:
Не нравится:
|
|||
11.03.2012, 11:32 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
Bond_JamesBondBond_JamesBond, Жесть. Установил Oracle 11g, он даже случай SELECT * FROM (SELECT * FROM A JOIN B ON B.key0=A.b ORDER BY B.x, B.key0) t0 WHERE rownum < 50; не разбирает. Хотя может я что-то не так делаю, буду еще разбираться... все верно, фулсканить гораздо эффективней: Код: 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. 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.
т.е. фулсканы дают в 1.5 раза меньше физических чтений и на порядок меньше логических. ... |
|||
:
Нравится:
Не нравится:
|
|||
11.03.2012, 14:13 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
Bond_JamesBond, пральна. Попробуй rownum<5 / LIMIT 5 или ещё раз в 10-100 увеличь таблицы. Yo. А че ты покрывающий индекс по соединяемым полям не сделал для SMJ? ... |
|||
:
Нравится:
Не нравится:
|
|||
11.03.2012, 14:38 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
Yo.!, Так а где использование B_x? То есть получается что она бежит по B полностью JOIN'ит NESTED'а с A, и потом идет все та же сортировка и отрезание. С использование B_x и A_b по определению не будет больше 50 чтений. А никакие не тысячи. Попробовал rownum <= 1 те же яйца. ... |
|||
:
Нравится:
Не нравится:
|
|||
11.03.2012, 19:03 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
впрягусь и попробую объяснить, как я понял вопрос Bond_JamesBond. SELECT * FROM A JOIN B ON B.key0=A.b ORDER BY B.x, A.key0 LIMIT 50; может ли какая-нибудь СУБД выполнять этот запрос таким образом: 1) по индексу B(x) выбрать все записи с минимальным значением x, 2) присоединить к ним nestedloop-ом записи из A по условию B.key0=A.b, 3) отсортировать полученный набор записей по A.key0, 4) выдать записи наружу, и проверить кол-во на лимит 50 5) если меньше лимита, вернуться к пункту 1 с условием выбирать записи с минимальным x строго больше значения x на предыдущем шаге ... |
|||
:
Нравится:
Не нравится:
|
|||
13.03.2012, 12:31 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
LeXa NalBat, ему уже все показали и разжували в оракловой ветке http://www.sql.ru/forum/actualthread.aspx?tid=925205 ... |
|||
:
Нравится:
Не нравится:
|
|||
13.03.2012, 12:48 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
LeXa NalBatвпрягусь и попробую объяснить, как я понял вопрос Bond_JamesBond. SELECT * FROM A JOIN B ON B.key0=A.b ORDER BY B.x, A.key0 LIMIT 50; может ли какая-нибудь СУБД выполнять этот запрос таким образом: 1) по индексу B(x) выбрать все 50 записи с минимальным значением x, 2) присоединить к ним nestedloop-ом записи из A по условию B.key0=A.b, 3) отсортировать полученный набор записей по B.x, A.key0 , 4) выдать записи наружу, и проверить кол-во на лимит 50 5) если меньше лимита, вернуться к пункту 1 с условием выбирать записи с минимальным x строго больше значения x на предыдущем шаге ... |
|||
:
Нравится:
Не нравится:
|
|||
13.03.2012, 15:00 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
все 50 нет, именно все строки с минимальным значением x, потому что присоединяющиеся строки с минимальными значениями A.key0 могут прийтись не на Ваши случайные 50 строк из B. (также соответствующих(-ей) строк(-и) для присоединения может не найтись в A.) B.x, A.key0 нет, достаточно отсортировать группу по A.key0, потому что все строки в группе имеют одинаковое значение B.x, и поэтому сортировка по A.key0 эквивалентна сортировке по B.x, A.key0. PS: неужели я тоже непонятно объяснил задачу? :) ... |
|||
:
Нравится:
Не нравится:
|
|||
13.03.2012, 17:16 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
LeXa NalBatвсе 50 нет, именно все строки с минимальным значением x, потому что присоединяющиеся строки с минимальными значениями A.key0 могут прийтись не на Ваши случайные 50 строк из B. (также соответствующих(-ей) строк(-и) для присоединения может не найтись в A.) B.x, A.key0 нет, достаточно отсортировать группу по A.key0, потому что все строки в группе имеют одинаковое значение B.x, и поэтому сортировка по A.key0 эквивалентна сортировке по B.x, A.key0. PS: неужели я тоже непонятно объяснил задачу? :) А если все B.x уникальны, то как оптимальней? ... |
|||
:
Нравится:
Не нравится:
|
|||
14.03.2012, 03:21 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
50А если все B.x уникальны, то как оптимальней?я не ставлю вопрос о выборе плана ("как оптимальней?") среди разных вариантов, ответ на который ищет планировщик (в постгресе planner). я спрашиваю, может ли какая-нибудь СУБД исполнить (в постгресе executor) такой план запроса. (предположим, что планировщик выбрал именно его.) (описанный мною план подошел бы и для уникальных B.x. особенность только в том, что каждый раз на первом шаге будет выбираться ровно одна строка с минимальным x. поэтому при наличии индекса A(b,key0) на втором шаге можно присоединять строки из A по этому индексу, и набор строк уже будет в нужном порядке, сортировка натретьем шаге в этом случае не нужна.) PS: придумал более простой пример, как мне кажется, на ту же тему. предположим в таблице A есть индекс по полю (f1). запрос: SELECT * FROM A ORDER BY f1, f2 LIMIT 50 может ли какая-нибудь СУБД выполнить этот запрос с использованием индекса по (f1), не пересортировывая все строки A? например по алгоритму: 1) по индексу A(f1) выбрать все записи с минимальным значением f1, 2) 3) отсортировать полученный набор записей по A.f2, 4) выдать записи наружу, и проверить кол-во на лимит 50 5) если меньше лимита, вернуться к пункту 1 с условием выбирать записи с минимальным f1 строго больше значения f1 на предыдущем шаге ... |
|||
:
Нравится:
Не нравится:
|
|||
14.03.2012, 10:04 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
50А если все B.x уникальны, то как оптимальней? В этом случае наличие A.Key0 в order by теряет смысл вместе с вопросом ТСа. Posted via ActualForum NNTP Server 1.5 ... |
|||
:
Нравится:
Не нравится:
|
|||
14.03.2012, 13:02 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
Dimitry Sibiryakov50А если все B.x уникальны, то как оптимальней?В этом случае наличие A.Key0 в order by теряет смысл вместе с вопросом ТСа.нет. потому что A.b не уникальны. и к одной строке из B с уникальным B.x может присоединиться несколько строк из A, эту группу нужно отсортировать по A.key0. ... |
|||
:
Нравится:
Не нравится:
|
|||
14.03.2012, 14:59 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
Bond_JamesBond... То есть join'им таблицы, сортируем, находим верхние 50 и фиг с ними с индексами. В итоге считывается вся база. Соответственно есть СУБД, которые догадываются бежать по B_x, для каждой записи бежать по A_b, выкидывая в результат соответствующие записи пока не наберется 50 записей? ... Код для СУБД CachéClass test.A Extends %Persistent { Index Ab On b; Property b As %Integer; ClassMethod Fill(isSmall As %Boolean = {$$$YES}) { ; удаляем данные do ##class(test.A).%KillExtent() do ##class(test.B).%KillExtent() ; заполняем данными if isSmall { for i=1:1:10000 &sql(insert into test.A set b=:i#100+1) for i=1:1:100 &sql(insert into test.B set x=:i*37#100) }else{ set N=1000000 for i=1:1:N set ^test.AD(i)=$lb("",i#100+1) set ^test.AD=N set N=10000 for i=1:1:N set ^test.BD(i)=$lb("",i*37#100) set ^test.BD=N ; строим индексы do ##class(test.A).%BuildIndices(,1,1) do ##class(test.B).%BuildIndices(,1,1) } ; настраиваем таблицы do $system.SQL.TuneTable("test.A",1,1) do $system.SQL.TuneTable("test.B",1,1) } } Class test.B Extends %Persistent { Index Bx On x; Property x As %Integer; } 10000/100 записей соответственно 1) Запрос по умолчанию select TOP 50 * from test.A JOIN test.B ON B.ID=A.b ORDER BY B.x, A.ID Быстродействие: 0.003 Секунд 615 глобальных ссылок Код: xml 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18.
2) Запрос с отключённым индексом Bx select TOP 50 * from %IGNOREINDEX test.B.Bx test.A JOIN test.B ON B.ID=A.b ORDER BY B.x, A.ID Быстродействие: 0.006 Секунд 1919 глобальных ссылок Код: xml 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18.
3) Все индексы отключены select TOP 50 * from %IGNOREINDEX test.A.Ab,test.B.Bx test.A JOIN test.B ON B.ID=A.b ORDER BY B.x, A.ID Быстродействие: 0.035 Секунд 40840 глобальных ссылок Код: xml 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17.
1000000/10000 записей соответственно 1) Запрос по умолчанию select TOP 50 * from test.A JOIN test.B ON B.ID=A.b ORDER BY B.x, A.ID Быстродействие: 0.015 Секунд 10713 глобальных ссылок Код: xml 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18.
2) Запрос с отключённым индексом Bx select TOP 50 * from %IGNOREINDEX test.B.Bx test.A JOIN test.B ON B.ID=A.b ORDER BY B.x, A.ID Быстродействие: 0.101 Секунд 91118 глобальных ссылок Код: xml 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18.
3) Все индексы отключены select TOP 50 * from %IGNOREINDEX test.A.Ab,test.B.Bx test.A JOIN test.B ON B.ID=A.b ORDER BY B.x, A.ID Быстродействие: 2.941 Секунд 4000840 глобальных ссылок Код: xml 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17.
10000000/100000 записей соответственно 1) Запрос по умолчанию select TOP 50 * from test.A JOIN test.B ON B.ID=A.b ORDER BY B.x, A.ID Быстродействие: 0.124 Секунд 102513 глобальных ссылок Код: xml 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18.
Caché for Windows (x86-64) 2012.2 (Build 528_1U) ... |
|||
:
Нравится:
Не нравится:
|
|||
14.03.2012, 20:30 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
LeXa NalBatпредположим в таблице A есть индекс по полю (f1). запрос: SELECT * FROM A ORDER BY f1, f2 LIMIT 50 может ли какая-нибудь СУБД выполнить этот запрос с использованием индекса по (f1), не пересортировывая все строки A?Если даже план оптимизатором выбран неэффективный, ему всегда можно подсказать. Например: Код для СУБД CachéClass test.C Extends %Persistent { Index idxF1 On f1; Property f1 As %Integer; Property f2 As %Integer; ClassMethod Fill() { do DISABLE^%NOJRN do ..%KillExtent() ; для ускорения заполнения таблицы случайными значениями для 100млн. записей использовался прямой доступ set N=100000000 for i=1:1:N { set f1=$random(50000)+i set f2=$random(i)+50000 set ^test.CD(i)=$lb("",f1,f2) //запись данных set ^test.CI("idxF1",f1,i)="" //запись индекса } set ^test.CD=N do ENABLE^%NOJRN do $system.SQL.TuneTable("test.C",1,1) } } Результат для 100млн. записей: Быстродействие: 0.005 Секунд 960 глобальных ссылок Код: xml 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22.
... |
|||
:
Нравится:
Не нравится:
|
|||
15.03.2012, 10:48 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
servitLeXa NalBatпредположим в таблице A есть индекс по полю (f1). запрос: SELECT * FROM A ORDER BY f1, f2 LIMIT 50 может ли какая-нибудь СУБД выполнить этот запрос с использованием индекса по (f1), не пересортировывая все строки A?select TOP 50 * from test.C where f1 in (select TOP 50 f1 from test.C order by f1) order by f1,f2нет. такой запрос не эквивалентен исходному. например в таблице A есть 100 строк с одинаковым минимальным значением f1. исходный запрос должен выдать те 50 из этой сотни, у которых меньше значения f2. а Ваш запрос сначала выберет случайные 50 строк из этой сотни, то есть может выбрать и с бОльшими значениями f1, в этом и ошибка, а потом их упорядочит. PS: как обсудили в этой и других темах (в постгресовом и оракловом разделах), можно так переформулировать запрос (CTE, unnest), чтобы он стал выполняться быстро по желаемому плану или приблизительно так. но интересует именно возможность выбора и исполнения сервером БД такого быстрого плана именно для такого простого запроса, без переформулировок. ... |
|||
:
Нравится:
Не нравится:
|
|||
15.03.2012, 11:16 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
servit, Cache зачет тогда... и луч позора Oracle и MSSQL. Смущает только без индексов для 1млн выполнение 2,5 секунды, остальные субд справляются за 300-500мс. Может к Cache адаптер сделать :)... Как у них кстати с SQL compliance, в смысле поддержка WINDOW функций, RECURSIVE CTE, и наличие каких-нибудь дебильных ограничений, типа того что временную таблицу нельзя юзать 2 раза в одном запросе (помню убило меня такое ограничение в MySQL). ... |
|||
:
Нравится:
Не нравится:
|
|||
15.03.2012, 11:25 |
|
LIMIT, JOIN и использование индексов
|
|||
---|---|---|---|
#18+
LeXa NalBat...а Ваш запрос сначала выберет случайные 50 строк из этой сотни...Запрос сперва выберет первые 50 минимальных уникальных значений поля f1 , затем на их основе выберет все строки из таблицы с этими значениями и уже отсортирует полученные строки по полям f1 и f2, ограничив затем результат до 50. Приведите пример данных, так как на моих данных (я пробовал несколько комбинаций) результаты в обоих случаях совпадают. ... |
|||
:
Нравится:
Не нравится:
|
|||
15.03.2012, 12:04 |
|
|
start [/forum/topic.php?fid=35&fpage=11&tid=1552577]: |
0ms |
get settings: |
10ms |
get forum list: |
12ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
29ms |
get topic data: |
13ms |
get forum data: |
3ms |
get page messages: |
130ms |
get tp. blocked users: |
2ms |
others: | 11ms |
total: | 218ms |
0 / 0 |