ЦП близок к 100% в цикле R - PullRequest
       0

ЦП близок к 100% в цикле R

0 голосов
/ 07 апреля 2020

Я пытаюсь создать запрос на лету с предложением IN в oracle. Проблема в том, что oracle не допускает более 1000 элементов в предложении IN, поэтому я использую несколько предложений IN, разделенных OR.

# expectedOutput has the values in column 1 which I have interest in 

uniqueCol <- df[4, 2]

teststring <- ""
teststring <- paste(uniqueCol, " in (", sep = "")
i <- 1
while (i < nrow(expectedOutput)) {
   if (i %% 1000 == 0) {
      teststring <- substr(teststring, 1, nchar(teststring) - 1)
       teststring<- paste(teststring, ") OR ", uniqueCol, " in (", sep="")
   }
   teststring <- paste(teststring, "'", expectedOutput[i, 1], "',", sep="")
   print(i)
   i <- i + 1
}

Это займет около 60 минут для работы на 8 ГБ, двухъядерный машина.

Как я могу ускорить это?

1 Ответ

1 голос
/ 07 апреля 2020

Проблема вызвана главным образом тем, что вы объединяете постоянно растущую строку teststring с новой подстрокой в ​​каждом раунде. Результатом является экспоненциально растущее время выполнения. Этот эффект усугублялся использованием целого data.frame на каждом шаге, а также строкой print(i). Их исправление значительно ускорит код.

На моей машине с 10000 строками в expectedOutput это занимает 6-7 секунд, для 50000 строк это занимает 2 минуты, для 100000 строк это занимает 6-7 минут и для 200000 строк требуется 24-25 минут для запуска исходного кода ниже. Это может быть уменьшено до 3-4 секунд для 50000 строк и всего лишь 11-12 секунд для 200000 строк с шагами, следующими за ним.

Сначала я смоделировал некоторые данные для теста:

expectedOutput <- cbind(
  db_col_name = c(paste0("A-", c(paste0("0", c(paste0("0", c(paste0("0", 0:9), 10:99)),
                                               100:999)), 1000:9999)),
                  paste0("B-", c(paste0("0", c(paste0("0", c(paste0("0", 0:9), 10:99)),
                                               100:999)), 1000:9999)),
                  paste0("C-", c(paste0("0", c(paste0("0", c(paste0("0", 0:9), 10:99)),
                                               100:999)), 1000:9999)),
                  paste0("D-", c(paste0("0", c(paste0("0", c(paste0("0", 0:9), 10:99)),
                                               100:999)), 1000:9999)),
                  paste0("E-", c(paste0("0", c(paste0("0", c(paste0("0", 0:9), 10:99)),
                                               100:999)), 1000:9999))),
  data.frame(replicate(100, sample(0:1000, 50000, rep=TRUE))))
uniqueCol <- "COLUMN_NAME"

Код был запущен для начального теста:

teststring <- paste(uniqueCol," in (", sep = "")
i <- 1
while(i < nrow(expectedOutput)){
  if(i %% 1000 == 0){
    teststring <- substr(teststring, 1, nchar(teststring) - 1)
    teststring <- paste(teststring, ") OR ", uniqueCol, " in (", sep="")
  }
  teststring <- paste(teststring, "'", expectedOutput[i, 1], "',", sep="")
  print(i)
  i <- i + 1
}

Удаление print(i) сократило время работы примерно на 1,6 минуты для 50000 строк.

Объединение подстрок в 1000 шагов, затем сохранение их в векторе, затем конкатенация вектора в конце значительно сократило время выполнения: около 5-6 секунд для 50000 строк:

teststring <- character(0)
teststr_tmp <- paste(uniqueCol," in (", sep = "")
i <- 1
while(i < nrow(expectedOutput)){
  if(i %% 1000 == 0){
    teststr_tmp <- substr(teststr_tmp, 1, nchar(teststr_tmp) - 1)
    teststr_tmp <- paste(teststr_tmp, ") OR ", uniqueCol, " in (", sep="")
    teststring <- c(teststring, teststr_tmp)
    teststr_tmp <- paste(uniqueCol," in (", sep = "")
  }
  teststr_tmp <- paste(teststr_tmp, "'", expectedOutput[i, 1], "',", sep="")
  i <- i + 1
}
teststring <- paste(teststring, collapse)

Наконец, поместив первый столбец expectedOutput в отдельный вектор дополнительно уменьшил время работы до 3-4 секунд для 50000 строк и всего 11-12 секунд для 200000 строк:

teststring <- character(0)
teststr_tmp <- paste(uniqueCol," in (", sep = "")
i <- 1
expectedOutputValues <- expectedOutput[[1]]
while(i < length(expectedOutputValues)){
  if(i %% 1000 == 0){
    teststr_tmp <- substr(teststr_tmp, 1, nchar(teststr_tmp) - 1)
    teststr_tmp <- paste(teststr_tmp, ") OR ", uniqueCol, " in (", sep="")
    teststring <- c(teststring, teststr_tmp)
    teststr_tmp <- paste(uniqueCol," in (", sep = "")
  }
  teststr_tmp <- paste(teststr_tmp, "'", expectedOutputValues[i], "',", sep="")
  i <- i + 1
}
teststring <- paste(teststring, collapse="")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...