|
|
|
| есть запрос
"SELECT tabl.[nomertel], sum(tabl.[summazvonka]) FROM tabl WHERE tabl.[summazvonka]<>0 and (((tabl.[opisanie]) Like '*(РЕГ)*')) group by tabl.[nomertel] "
таблица tabl содержит более 2 000 000 записей.
запрос работает, но выполняется в течении 5-10минут. хочется быстрее. | |
|
| |
|
|
|
| null в summazvonka есть?
может их так nz([summazvonka],0)<>0 ?
или может вообще убрать?
всмысли хавингом потом, после суммирования?
или может сперва выборку сделать, а уже потом агрегацию?
а nomertel- ключевое? если нет, то может - сделать?
а opisanie не MEMO? то может если МЕМО, то instr, может, попробовать?
хотя лайк, вроде хорош.... | |
|
| |
|
|
|
| если сделать выборку , и записать ее в таблицу , а потом делать агрегацию, то агрегация делается быстро.
но вот сама запись в таблицу заниает кучу времени около 5минут.
может я неправильно както записываю в таблицу?
подскажите как правильно рекордсет записать в таблицу? или ее вообще можно не записывать, а как то сам рекордсет суммировать? | |
|
| |
|
|
|
|
но вот сама запись в таблицу занимает кучу времени около 5минут.
|
--сколько записей выбирается 1-10-1000-10000 | |
|
| |
|
|
|
| более 300 000 записей выбирается | |
|
| |
|
|
|
| с повторными --300 000 записей
а уплотненных, с итогами | |
|
| |
|
|
|
| уплотненых с итогами уже порядка 150 | |
|
| |
|
|
|
| insert - долго
create table - быстро | |
|
| |
|
|
|
| через create table я не знаю как вугрузить значения рекордсета, что то никакк не додумкаю. | |
|
| |
|
|
|
| аттачишь текстовый файл
и обращаешься к нему запросом
или, может ещё лучше(?надо проверять практически),
трансформ текстового файла сразу в таблицу акса
при условии, что данные в нормальном виде представлены | |
|
| |
|
|
|
| так и делаю, (еслия парвильно поянл) загружаю таблицу в отднельный файл акса, а далее уже из своего клиента к нему подключаюсь. | |
|
| |
|
|
|
|
(tabl.[opisanie]) Like '*(РЕГ)*'
| Тормоз здесь. А это "(РЕГ)" действительно в любой части текста? Что это обозначает? Как в таблицу вносятся записи? Может есть смысл добавить логическое или числовое поле для признака? Таблица родная или доступ по сети? | |
|
| |
|
|
|
| как думаешь, регекспом быстрее будет?
в оракле лайк шустр :) | |
|
| |
|
|
|
| таблицу присылает оператор связи (детализация всех звонков по всем абонентам более 2500абонентов), в текстовом формате.
(РЕГ) признак у них обозначает звонок во внутрисетевом роуминге, другого обозначения у них нет. впереди может быть еще один символ , он может быть любым
соответственно, я просто заливаю таблицу в аксес , а далее обрабатываю так как мне надо.
на самом деле если я сейчас научусь делать данную выборку быстро, у меня еще парочка запросов, котрые работают переделаются по данному алгоритму. | |
|
| |
|
|
|
| может так (хотя не уверен)
SELECT t.nomertel AS Выражение1, (select sum ( r.summazvonka) as wer
from Tabl as r where r.nomertel=t.nomertel) AS сумма
FROM [SELECT s.nomertel
FROM Tabl as s
where s.opisanie like '*рег*']. AS t
GROUP BY t.nomertel
HAVING ((((select sum ( r.summazvonka) as wer
from Tabl as r where r.nomertel=t.nomertel))<>0)) | |
|
| |
|
|
|
|
|
я просто заливаю таблицу в аксес
| Как заливаете? В существующую таблицу? Пустую?
Заливать можно запросом INSERT INTO, в нем добавить вычисляемое поле IIF(tabl.[opisanie]) Like '*(РЕГ)*', True, False), результат которого вносить в логическое поле таблицы. Ну или после импорта выполнить запрос UPDATE для этого поля.
А потом это поле использовать в условиях запроса. | |
|
| |
|
|
|
| т.е. идея подготовить предварительно начальную табличку.
впринципе понятно. хотелось просто заливать талицу и работать, но раз нельзя значит нельзя | |
|
| |
|
|
|
| Поэксперементировал
на 2 700 000 записях
тот запрос что я вам выше написал
отрабатывает у меня за 44 сек
запрос с которого начался топик - за 33 сек
запрос с дополнительным столбцом в таблице - за 19 сек
(основное время тратится на группировку почему-то) | |
|
| |
|
|
|
| А поле "nomertel" индексировано? | |
|
| |
|
|
|
| нет не индексированно. попробовал проиндексировать (с повторениями) но не особо быстро получилось. | |
|
| |
|
|
|
| вот просто выбрать нужные записи , вопросов нет, запрос отрабатывается быстро.
далее если записать выборку в темповую таблицу - здесь время уходит. , но зато потом операция с групировкой быстро отрабатывает.
и если делать сразу выборку с группировкой тоже время много уходит. | |
|
| |
|
|
|
| --создайте пустую бд c:\pusto.mdb
--
filecopy c:\pusto.mdb c:\mrab1.mdb
s1="select ......into rab1 in 'c:\mrab1.mdb'"
docmd.runsql s1
|
отчеты делать со связанной таблицы rab1
скорость выше, т.к. рабочая мдб --пустая | |
|
| |
|
|
|
|
хотелось просто заливать талицу и работать
| Ві не ответили ни на один мой вопрос.
Если "просто заливать талицу", то можно и не заливать, а прилинковать.
Если импортировать в новую таблицу, то после єтого можно в нее и индексы добавить, и поле, и заполнить это поле.
Но правильнее - заливать в заранее подготовленную таблицу. | |
|
| |
|
|
|
| Мне казалось, что выше есть ответы на эти вопросы.
я создаю файл mdb, туда импортирую данные в обычную таблицу. (просто импорт файла)
далее из клиента просто обращаюсь к этому файлу, и выбираю те данные, котрые мне нужны. | |
|
| |
|
|
|
| генератор ваших данных, например
'-- Task Tabl3K
Function rnd999()
Randomize
rnd999 = Int((999 * Rnd))
End Function
Function rnd99()
Randomize
rnd99 = Int((99 * Rnd))
End Function
Function rndAz(Optional upperbound = 254, _
Optional lowerbound = 192, _
Optional asChar As Boolean = True)
Dim ir&
On Error GoTo err123
Randomize
ir = CInt(Math.Round((upperbound - lowerbound + 1) * Rnd())) + lowerbound
If asChar Then
rndAz = Chr(ir)
Else
rndAz = CInt(ir) + lowerbound
End If
Exit Function
err123:
rndAz = "#"
Exit Function
End Function
Function task_Tabl3k(Optional cRec& = 1, _
Optional dmode As Boolean = True)
Dim rs As DAO.Recordset
Dim i&, j&, ii&, s&, sr&, tel$, am@, note$
On Error GoTo err123
If cRec < 1 Then cRec = 1
If dmode = False Then CurrentDb.Execute "delete * from Tabl", dbFailOnError
SysCmd acSysCmdSetStatus, "заполнено: " & 0 & " из " & cRec
For i = 1 To cRec
tel = "(" & Format(rnd99(), "000") & ")" & Format(rnd99(), "00") & "-" & Format(rnd999(), "000") & "-" & Format(rnd999(), "000")
am = rnd99() / 100
note = ""
ii = CInt(Math.Round((50) * Rnd())) + 1
For j = 0 To ii
s = CInt(Math.Round((ii) * Rnd()))
If s = 0 Then s = 1
If j Mod s = 0 Then
note = note & Chr(32)
End If
note = note & rndAz()
Next j
sr = (Math.Round((cRec - 1 + 1) * Rnd()))
If sr > 0 Then
If sr Mod 2 = 0 Then
note = Replace(note, " ", "рег ")
End If
End If
note = Left(LTrim(note), 255)
If dmode = True Then
Debug.Print "tel=" & tel, "am=" & am, "note=" & note
Else
CurrentDb.Execute "insert into Tabl(nomertel,summazvonka,opisanie) " & _
"values('" & tel & "'," & am & ",'" & note & "')", dbFailOnError
End If
SysCmd acSysCmdSetStatus, "заполнено: " & i & " из " & cRec: DoEvents
Next i
Exit Function
err123:
MsgBox Error, , "task_Tabl3k"
SysCmd acSysCmdClearStatus
Exit Function
End Function
|
пока заполняю таблицу 2мя миллионаме
| |
|
| |
|
|
|
| >пока заполняю таблицу 2мя миллионаме
------------------------
--заполнить мдб терпения не хватило
--создала текстовик
--прилинковала
--базовый запрос --21 секунда
SELECT [1256].tel, Sum([1256].am) AS [Sum-am], First([1256].note1) AS [First-note1]
FROM 1256
WHERE note1 like '*reg*' and am>0
GROUP BY [1256].tel;
|
похоже;причина замедления --размер мдб
--у меня он 700кб
--у вас видимо 700мб
запросы плохо работают при раздувании мдб | |
|
| |
|
|
|
| мне интересно было реализовать замысел по формированию псевдоданных :) | |
|
| |
|
|
|
|
''полной очистки от лишнего не делала, так немного
Function task_Tabl3kp(Optional cRec& = 1, _
Optional dmode As Boolean = True)
Dim rs As DAO.Recordset
Dim i&, j&, ii&, s&, sr&, tel$, am@, note$, s1, j2
'On Error GoTo err123
If cRec < 1 Then cRec = 1
If dmode = False Then CurrentDb.Execute "delete * from Tabl", dbFailOnError
SysCmd acSysCmdSetStatus, "заполнено: " & 0 & " из " & cRec
Open "c:\rab\1256.txt" For Output As #1
Print #1, "tel;am;note1"
j2 = 0
For i = 1 To cRec
tel = "(" & Format(rnd99(), "000") & ")" & Format(rnd99(), "00") & "-" & Format(rnd999(), "000") & "-" & Format(rnd999(), "000")
am = rnd99() / 100
note = ""
ii = CInt(Math.Round((30) * Rnd())) + 1
For j = 0 To ii
s1 = Chr(CInt(Math.Round((ii) * Rnd())) + 40)
note = note & s1
Next j
'If InStr(note, "44") > 0 Then
If note Like "*4*4*" Then
note = note & "(reg) "
j2 = j2 + 1
If note > "999" Then
Debug.Print "="; i; j2;
End If
End If
If dmode = True Then
'Debug.Print "tel=" & tel, "am=" & am, "note=" & note
Print #1, tel, ";"; am; ";"; note
Else
CurrentDb.Execute "insert into Tabl(nomertel,summazvonka,opisanie) " & _
"values('" & tel & "'," & am & ",'" & note & "')"
', dbFailOnError
End If
' Debug.Print acSysCmdSetStatus, "заполнено: " & i & " из " & cRec: DoEvents
' SysCmd
Next i
Close #1
Exit Function
err123:
MsgBox Error, , "task_Tabl3k"
SysCmd acSysCmdClearStatus
Exit Function
End Function
|
| |
|
| |
|
|
|
| тут вы правы объем сразу после импорта таблицы более 1,3Гб. после сжатия около 950Мб. | |
|
| |
|
|
|
| в таблицу добавьте поле status
в котором будет 1 или 0 в зависимости от like "*рег*"
по этому полю сделайте индекс
на 2 000 000 записях у меня суммирование с группировкой по номеру телефона заняло порядка 40 секунд | |
|
| |
|
|
|
| уже тоже попробовал.
да чутток побыстрее стало, но блин сама операция на обновление поля status в зависимости от лайка тоже заняла доброе количество времени :). так что я подумал, пущай пользователи ждут окончания запроса. :) благо пользующихся данным запросом не так много. (ох уж эти бухгалтера) | |
|
| |
|
|
|
| значит надо поработать над алгоритмом(запросом) который бы быстро выставлял статус :)
например заливать(подготавливать) таблицу ночью :)
чтобы конечный пользователь мог работать с готовыми данными, не требующими дополнительной обработки
если это возможно, конечно | |
|
| |
|
|
|
| >тут вы правы объем сразу после импорта таблицы более 1,3Гб. после сжатия около 950Мб.
-------------------------
таблица должна быть в другой базе--не программной
программная --не более 1-3 мб, таблица --линковка | |
|
| |
|
|
|
| так и есть.
один момент только хочу уточнить .
я не большой асс в программировании. поэтому по поводу линковки хотел бы уточнить.
я открываю таблицу следующим образом
Set db = DBEngine.Workspaces(0).OpenDatabase("путь к моей таблице в виде \\ser1\.....\....mdb")
Set RstKont = db.OpenRecordset("здесь мой запрос по группировке и суммированию")
может я не правильно делаю? | |
|
| |
|
|
|
| каков объем программной базы
запрос --вроде все так, ошибки не замечаю
---но напишите полное имя, необязательно реальное
---главное чтобы пробелы,кавычки и слеши совпадали
"\\serv1\ddd\hhh hhhh hhhh\aaa.mdb"
--какой разделитель применяете в запросе | |
|
| |
|
|
|
| объем клиента 1,5Мб
у меня это все работает, вопрос не в этом. там ошибок не с раздилителями не с именами нет.
я просто подумал, может я не правильно понял и вы имели ввиду что-то другое под словом "линоквать" | |
|
| |