안녕하세요.
대용량데이타를 기반으로 한 계산값 도출시, 엑셀계산속도를 빠르게 하려고 궁리를 하다가 봉착한 문제인데 조언을 듣고자 합니다. 제가 셀에 최종결과값을 도출할 때 2가지 방식을 사용중인데 이 중에 무엇이 빠른 지를 알고자 합니다. 다음과 같이 2가지 방식 testA, testB 를 말씀드리겠습니다.
우선 아래는 testA 이고, 이 결과값은 A1 셀에 입력합니다. ( 이하 A 라 칭함 )
제가 속도를 빠르게 하고싶다고 말씀드렸는데 어떤 속도냐면 그것도 여기 예에서 함께 설명합니다.
예: testA의 속도 : 3과 4를 더하기하여 7을 도출해내는 속도... 가 아니라....도출한 결과값 7을 A1셀에 뿌려주기까지의 속도라고 해야 더 정확하겠죠.... 가 아니라.. 이 7을 받아서 다른 곳에서 재계산을 수행하게끔 해주는 속도...라고 해야 정확할려나요(주석A: 제 질문이 왜 이런지는 아래에 설명)
Public var_a As Integer, var_b As Integer
Sub Gen()
var_a = 3
var_b = 4
End Sub
Sub testA()
Call Gen
a = var_a
b = var_b
Range("A1").Value = a + b '// <--셀접근. 여기가 시간잡아먹는 곳
End Sub아래는 testB 이고, 이 결과값은 A2 셀에 입력합니다. ( 이하 B 라 칭함 )
예: 셀에 입력된 각각의 파라미터 3과 4를 받아 7을 도출하여 이 7을 B1셀에 뿌려주.....고 말것도 없이 .. 이건 Function 이니까 리턴값으로 자동입력되겠네요. B1셀에는 =testB(B2,C2) 입력되어 있으니까요. 이렇게 3+4=7을 더하여 여기 셀에 뿌려주고.. 가 아니라.. 다른 곳에서 이 7을 가지고 재계산할 수 있게끔 해주는 속도. 여기도 말이 이상하지만...
'// B1 셀값 변동, B1셀에는 =testB(B2,C2) 입력됨, 파라미터 a, b 는 3과 4 임
Function testB(a As Integer, b As Integer)
testB = a + b
End Function
위 A 와 B 중 어떤 방식이 속도가 더 빠를까요? 중요포인트는 이 결과값 A, B 로 다른 계산을 해야합니다. 그래서 최대한 빠르게 결과값을 받아 다른 계산을 준비해야 합니다. 그리고 그게 또 다른 계산을 합니다. 위는 질문을 위하여 작성한 간단예제이고 실제 데이타는 대용량이고 수없는 반복계산을 하므로 결과값도출까지 시간이 걸리는 이슈가 있습니다. 저런 testA testB 같은게 수만개 셀 적재적소에서 동시다발 계산중이라 무슨 방식이 빠르냐가 큰 고민거리가 되는 상황입니다.
A에 대한 저의 의견 :
제가 가장 두려워하는 문제가.... 여기 게시판을 통하여 공부하면서 알게된 사실이 [ 최대한 Cell.Value 접근을 줄이고, 메모리상에서 계산이 이루어져야 한다] 는 점인데요. 그런데 A 방식은 Range("A1").Value = a + b 에서 셀접근을 해야합니다. A1에 7을 뿌려주는 행위가 셀접근이잖아요. 여기 예제파일에서는 딱 1번뿐이지만 실제파일은 이런 셀접근이 자주 있습니다. 예를 들어 B546 셀을 받아서 aaa 라는 변수에 저장해라. 이런 식으로요. 이 점때문에 속도저하가 발생할 수도 있겠다는 두려움이 있습니다. 그래서 제가 위에서 (주석A: 제 질문이 왜 이런지는 아래에 설명)를 적어놓은 이유이고요. 결과값 7을 도출한 속도라기보다 이 7을 셀에 입력시키기까지의 속도라고 봐야 정확하다고봅니다. 맞나요?
B에 대한 저의 의견 :
위 A에서 셀접근 두려움때문에 생각해 낸게 Function 이었습니다. 그리고 저는 이 function방식이 A보다 속도가 더 빠를 것으로 이해하고 있었습니다. 왜냐면 셀접근 필요없이 셀 그 자체에서 계산이 이루어지니까요(그리고 VBA가 아니어 인터프리터 방식이 아니고요. 맞는 말인지 모르겟지만). 위 A방식에서는 A1셀에 7을 뿌려라.. 이 행위가 셀접근인데 이 B 방식은 [ 내가 이미 function 으로 여기 A1 방에 입주해있다. 그러니 난 A1 방을 찾을 필요없이..시간지체없이.. 이 방에서 곧장 7을 꺼내버리면 된다. 그래서 7 결과값나오자 마자 이것으로 끝. 속도지연없음 ]
... 라고 생각했었는데 지금은 생각이 바뀐게 [ 근데 넌 셀수식이 =testB(B2,C2) 라면 이것도 어차피 B2, C2 셀 접근을 해야 하지 않냐? 그러면 이것도 속도가 느려질 수 있다 ] 라고 생각이 들엇습니다. 그래서 A B 누가 더 빠를까? 결론을 못내다가....
현재 저의 생각 :
그런데 자꾸 공부하다보니... 저 A, B 에서 말한 속도에 대한 정의부터 엑셀지향적이지 않고 인간지향적인 오해일 수도 있다는 우려가 새로 생겼습니다. 왜냐하면 셀접근 빈번하면 속도가 느려지는건 이해하지만(이건 확실히 제가 이해했습니다), 위에서 말한 [ 결과값을 셀에 입력시키는 시간 ] 은 [ 우리 인간에게 시각적으로 그 셀이 업데이트된 것을 느끼게 하려는 것일뿐, 엑셀은 이미 7을 받아서 셀에 뿌려주기 전에, 이미 다른 계산까지도 하러 이미 떠나버렸다(즉 엑셀은 인간의 눈으로 확인은 엄두도 못낼만큼 훨씬 더 속도가 빠르다) 즉 7을 가지고 또 다른 계산, 또 다른 게산, 또 다른 게산.... 을 이미 1천번도 더 했는데.. 셀에 7이 입력되어지는 건 그 1천번 재계산 이후의 일일 수도 있다. 쉽게 말해... KTX 가 광명을 지날때, 광명역 전광판에 [ 기차가 접근하고 잇다] 라고 안내할때, 이미 이 기차는 대전까지도 도착해 있다(대전승객탑승중 = 다음 계산 수행중) 인 것과 같은 상황이다. 기차가 전광판보다 더 빠르다. 왜 이런 생각을 했냐면요. 이미 7 이라는 결과값은 메모리 상에 저장되어 있잖아요. 그러면 엑셀입장에서는 이 값을 셀에 뿌려주고 말것도 없이 다른 계산을 수행할 수 있잖아요. 즉 셀에 7이 입력된 건, 이미 엑셀이 이 7을 가지고 1천번도 더 재계산을 한 이후에 일어난 일일 수도 있잖아요.
여기에서 꼭 확실히 정의해야할 것 : 셀접근 빈번. 이 말은 제가 확실히 이해했습니다. 근데 여기에서 말한 셀접근과 셀업데이트는 구분해야 함. 어쨌든 엑셀이 셀업데이트 7 입력시키는 것을 속도에 포함시키면 안된다.
...라는 것이 현재 저의 생각입니다.
....라고 생각도 들지만 꼭 그런것 같지도 않아요. 내가 모르는 엑셀의 비밀이 또 잇다는 느낌이 또 듭니다. 어쨋든 현재까지 제 이해는..
이미 너무 속도가 빠르게 다른 계산으로 넘어가버렸는데.. (인간에게 시각적으로 보여주기 위한 걸 두고) 속도계산에도 포함시키면 안된다. 그래서 셀에 입력시키는 시간을 두고 속도 운운하는 건 기우이다. ] 라는 것입니다. 아~ 제 질문을 상세하게 드리고 싶은데.. 늘 느끼지만, 중언부연할수록 이상해지는 느낌도 있네요. 요약하면 아래와 같습니다.
조건: 결과값을 꼭 셀에 입력해줘야함. 메모리에서만 가지고 잇으면 안됨.
질문 1 : 결과값 도출까지 위 A, B 중 누가 더 빠른가?
질문 2 : 위 A, B 에서 받은 결과값으로 다른곳에서 다른 재계산 수행시 A, B 는 누가 더 빠르게 그 계산들을 도와줄까? ( 참조가 용이해질까? )
감사합니다.
안녕하세요~
질문 속에서
엑셀의 계산 속도와 셀 접근(Cell Access), 그리고 화면 갱신(Display Update) 사이의 관계까지 상당히 깊이 고민하고 계신지가 느껴지네요.
특히 “KTX 기차와 전광판”의 비유는 엑셀의 Calculation Chain(계산 사슬)과 Screen Updating(화면 갱신)의 관계를 잘 표현한 거 같습니다.
1. 질문의 내용은
대용량 데이터 처리 시 “VBA와 시트(Sheet) 사이의 데이터 교환(인터페이스)”에서 발생하는 병목 현상을 우려하고 있는데,
- TestA (Sub 방식)는 VBA에서 계산 후 셀에 값을 “던져주는” 방식으로 셀 접근 비용을 걱정하고 있지만, 예시로 제시하신 `Range("A1").Value = a + b`는 단일 셀 예시라서, 실제 “대용량 데이터”를 처리할 때 TestA가 어떻게 작동하는지에 대한 설명이 살짝 부족합니다.
1만 개의 행을 처리할 때 For문(반복문)을 돌면서 `Cells(i, 1) = 값`을 1만 번 수행하는지, 아니면 배열에 담았다가 한 번에 뿌리는지 명시는 안 되어 있지만, 질문 맥락상 “셀마다 찍는 방식”을 우려하시는 것 같긴 합니다.
- TestB (Function 방식)은 셀 수식으로 존재하며 값을 “끌어오는” 방식으로 셀에 상주하니 더 빠르지 않을까? 하는 기대가 있는 듯 보입니다.
그리고 KTX 비유를 통해
“셀에 값이 찍히는 시각적 행위(전광판)보다 엑셀 내부 계산(기차)이 훨씬 빠르니, 셀 접근 비용은 무시해도 되는 거 아닐까?”라는 질문을 던지셨습니다.
이러한 상황을
“대형 뷔페 식당(엑셀 시트)”과 “주방(VBA 메모리/CPU)”으로 비유해 보겠습니다.
- 엑셀 시트(Sheet)는 손님들이 앉아 있는 홀(데이터가 보여지는 곳),
- VBA(Memory)는 요리를 만드는 폐쇄된 주방(계산이 이루어지는 곳),
- 셀 접근(Cell Access)은 주방에서 홀로 나가는 “문(Door)을 여닫는 행위”로 볼 수 있습니다.
그럼,
■ 상황 A: TestA (Sub 방식 : 셀 단위 접근)
“요리사가 볶음밥 10,000그릇을 서빙하는 상황”입니다.
요리사가 주방에서 볶음밥 한 그릇을 만듭니다.
→ 주방 문을 열고 나가서 A1 테이블에 놓습니다.
→ 다시 주방으로 들어와 문을 닫습니다.
→ 다시 한 그릇을 만들고 문을 열고 나가 A2 테이블에 놓습니다.
…
이럴 때 문제점은,
문을 10,000번 열고 닫아야 하는데 이 “문을 여닫는 시간(인터페이스 비용)”이 실제 요리하는 시간보다 더 걸리면서 전체 속도가 매우 느려진다는 점입니다.
■ 상황 A+: TestA+ (Sub 방식 - 배열 처리 최적화)
이 과정을 업그레이드하면,
“요리사가 카트(Array)를 쓰는 상황”으로 바꿀 수 있습니다.
요리사가 주방에서 볶음밥 10,000그릇을 다 만든 다음,
이걸 커다란 서빙 카트(Array)에 한 번에 다 싣고,
주방 문을 딱 한 번 열고 나가서
한 번에 쫘르륵 테이블에 깔아버립니다.
문을 1번만 열었으므로, 이 방식이 가장 빠르고
TestA+가 지향해야 할 방향으로 볼 수 있습니다.
■ 상황 B: TestB (Function 방식 - UDF)
“테이블마다 출장 요리사를 부른 상황”으로 볼 수 있습니다.
각 테이블(Cell)마다 요리사가 한 명씩 배치됩니다(= TestB 함수).
이 요리사는 재료(B2, C2)를 확인하기 위해 옆 테이블을 봅니다(셀 읽기).
요리를 해서 자기 테이블에 놓습니다.
언뜻 보면 깔끔하고 좋아 보이지만,
엑셀 입장에서 “VBA 함수”를 호출하는 건 “VBA라는 외주 업체”를 부르는 것과 같습니다.
10,000개의 셀이 있다면 엑셀은 10,000번 외주 업체(VBA 엔진)를 호출해야 합니다.
문을 여닫는 횟수(인터페이스 비용)는 상황 A(셀 단위)와 비슷하게 많고,
게다가 엑셀 내장 함수(SUM, VLOOKUP 등)에 비해 최적화가 덜 되어 있어 이 또한 느립니다.
2. 그럼, 결과값 도출까지 A, B 중 누가 더 빠른가요?
물론 “작은 데이터”에서는 차이가 거의 없겠지만,
질문 주신 것처럼 "대용량 데이터"에서는 배열을 사용한 TestA+ (Sub 방식 - 배열 처리 최적화) 방식이 압도적으로 빠릅니다.
TestA+ (Sub 방식 - 배열 처리 최적화)는,
- 메모리(주방)에서 모든 계산을 끝내고,
'Range("A1:A10000").Value = 배열' 형태로
딱 한 번만 셀에 접근하는 방식입니다.
KTX 비유에서 말씀하신
“메모리 상에서 이미 계산 끝났다”를 실현하는 유일한 현실적인 방법이기도 합니다.
반면에, TestA (셀 단위 반복 루프)와 TestB (UDF)는
- 둘 다 “셀 또는 VBA 엔진에 자주 왕복”해야 하므로 대용량(수만 행) 데이터라면 둘 다 버벅거릴 수 있고,
- 일반적으로 VBA UDF(TestB)는 엑셀 내장 함수(SUM, VLOOKUP 등)보다 훨씬 느리며,
- 싱글 스레드로 동작하는 경우가 많아 대량 사용 시 병목이 심해집니다.
- 더군다나 For문 안에서 'Cells(i, 1) = 값'을 수행하는 것도 매번 셀 접근(문 여닫기)을 하기 때문에 대단히 느릴 수 있습니다.
여기서 하나 더 중요한 개념이 있습니다.
많은 분들이 TestA와 TestB를 비교할 때 “연산 속도”만 놓고 고민하지만,
엑셀은 단순 계산기가 아니라 “재계산 엔진(Calculation Engine)”을 가진 구조입니다.
즉, 엑셀은 셀을 계산할 때 이렇게 판단합니다.
- 숫자(예: 7)는 이미 계산된 결과값(단순 데이터)으로 다시 계산하지 않고
- 수식(예: '=testB(B2,C2)')은 “계산해야 유지되는 셀”로 값이 변경되거나 종속된 셀이 변경되면 재계산합니다.
이걸 Dependency Tree(의존성 트리)라고 하는데,
- TestA는 결과값이 정적인 값(숫자)이므로 엑셀은 그 셀을 “계산 대상”에 포함하지 않습니다.
- TestB는 수식이 남아 있으므로 엑셀은 그것을 “계산해야 하는 셀”로 인식합니다.
즉, 두 방식의 진짜 차이는 단순한 연산 속도가 아니라,
엑셀이 그 값을 “다시 계산해야 하는 객체로 보느냐”에도 있습니다.
3. 이런 상황에서, 두 번째 질문인
“참조 용이성 관점에서는 재계산 시 누가 더 빠르게 도와줄까?”를 보면,
결론부터 말씀드리면 A 방식(값으로 붙여넣기)가 더 유리합니다.
- TestA (값 고정)에서는 계산이 끝나면 셀에는 그냥 숫자 7만 남는데,
다른 셀이 이 7을 참조할 때, 엑셀은 그냥 숫자만 읽어가면 돼서 매우 빠릅니다.
단점은 원본 데이터가 바뀌면, 매크로를 다시 실행해서 값들을 새로 갱신해 줘야 합니다.
- TestB (UDF)에서는 셀에 '=testB(B2,C2)'라는 수식이 남는데,
다른 곳에서 이 값을 참조하려 할 때, 만약 testB가 아직 계산이 안 끝났거나,
엑셀이 “이거 다시 계산해야겠는데?”라고 판단하면(Volatile 상태 등),
다시 VBA 엔진을 깨워서 계산을 시킵니다.
이 부분이 위에서 언급한
재계산(의존성) 트리(Dependency Tree)에 부하를 주는 부분입니다.
따라서,
- “한 번 셀에 숫자 7이 들어간 후, 다른 셀에서 그 값을 참조하는 속도” 자체는 A/B 차이가 거의 없지만, “그 7을 다시 계산해야 할 때”는 VBA로 한 번에 돌려 "값만 남기는 방식(TestA+)"이 재계산 비용이 더 적습니다.
4. KTX 비유(시각적 업데이트)에 대한 팩트 체크를 하자면,
질문자님의
“엑셀은 이미 계산을 끝내고 다른 곳을 달리고 있다”는 생각은
반은 맞고, 반은 틀립니다.
- 맞는 점은 Application.ScreenUpdating = False를 쓰면,
엑셀은 화면(전광판)을 갱신하는 리소스를 아껴서 계산(기차)에 집중합니다. 따라서 실제로 속도가 빨라집니다.
- 틀린 점은 그렇다고 해서 “셀에 값을 넣는 행위(Value 입력)” 자체가 “계산과 무관한, 단순 시각적 행위”인 것은 아닙니다.
VBA 변수 a = 7 (메모리) → 엑셀 시트 Range("A1").Value = 7 (셀)
이 과정은 메모리 복사와 COM 인터페이스 통신이 일어나는 "실제 작업 시간"입니다.
단순히 “보여주기 위한 시간”이 아니라,
주방에서 만든 요리를 홀까지 직접 들고 나가는 것과 같아서
손님 눈에 보이든 안 보이든 “이동 시간”이 분명히 존재하는 노동입니다.
5. 결론적으로
질문자님은 대용량 데이터를 다루고, 속도가 중요하며, VBA를 다룰 줄 아십니다.
그렇다면 실무적으로는 대부분 TestA+가 훨씬 유리합니다.
아래 예제처럼
TestA+ 방식으로 [배열 처리]를 하시면 됩니다.
한번 테스트해보세요,
입력 측면에서 Range를 Variant 변수(배열)에 한 번에 담습니다.
(주방으로 재료 카트 반입)
'// 1. [입력] 주방 문 딱 1번 열고 재료(A,B열)를 카트에 싣기 arrInput = Range("A1:B" & eRow).Value계산 측면에서는 VBA 메모리 안에서 배열끼리 지지고 볶고 계산합니다.
(주방 문 닫고 미친 듯이 요리 - KTX 속도)
출력에서는 결과 배열을 Range에 한 번에 뿌립니다.
(완성된 요리를 카트로 한 번에 서빙)
'// 4. [출력] 주방 문 딱 1번 열고 완성된 요리(C열) 쏟아붓기 Range("C1:C" & eRow).Value = arrOutput이 방식이 TestB보다 수십 배에서 수백 배 빠를 수 있고,
“배열 처리나 딕셔너리 처리”가 바로 이 문제를 해결하는 핵심 열쇠입니다.
Sub 2_TestA배열() Dim t As Double Dim i As Long Dim eRow As Long Dim arrInput As Variant '// 재료를 담을 카트 (입력 배열) Dim arrOutput As Variant '// 요리를 담을 카트 (출력 배열) t = Timer eRow = 30000 '// 1. [입력] 주방 문 딱 1번 열고 재료(A,B열)를 카트에 싣기 arrInput = Range("A1:B" & eRow).Value '// 2. 결과값을 담을 빈 카트 준비 (행 개수만큼, 1열짜리) ReDim arrOutput(1 To eRow, 1 To 1) '// 3. [계산] 주방(메모리) 안에서 미친듯이 요리하기 (KTX 속도) '// 이 루프는 셀 접근이 전혀 없어서 순식간에 끝납니다. For i = 1 To eRow arrOutput(i, 1) = arrInput(i, 1) + arrInput(i, 2) Next i '// 4. [출력] 주방 문 딱 1번 열고 완성된 요리(C열) 쏟아붓기 Range("C1:C" & eRow).Value = arrOutput MsgBox "배열(Array) 처리 소요시간: " & Format(Timer - t, "0.00") & "초" End Sub
수메리안 선생님 안녕하세요.
제 질문의 의도를 어쩜 이리도 잘 캐치해주시나 감동하며 또 글을 읽고 있습니다. 저의 고민에 대한 출발점은 계산속도를 더욱 빠르게 조치하려할 때 저 Cell.Value 접근에 대한 엑셀구동원리를 잘 모르고 있다는 데에 있었습니다. 예를 들어 [ A1 에 입력된 값 7 을 다른 곳에서 참조한다 ] 라는 이 행위에 대한 것을 엑셀의 입장에서 생각하면, 이 사건의 전후관계는…
계산값 7이 도출되었다. (여기까지 의문이 없음) ---->
이 값을 B1셀이 참조한다. (여기까지 의문이 없음)---->
그럴려면 A1 셀에 7이 입력되어 있어야 한다. (여기까지 의문이 없음)---->
왜냐면
Range("B1").Value = Range("A1").Value이라고 해야할테니까요. 또는 변수 a 에 저장한다 해도
a = Range("A1").Value이라고 해야할 테니까요. 참조를 할려면 어떤 식으로든 셀에 접근 또는 셀을 터치해야한다는 의미입니다.
그렇다면 이 지점에서 사건의 전후관계를 더욱 정밀하게 파악해보겠습니다. A1셀에 7이 입력되는 사건은 변수에서 변수로, 또는 메모리에서 메모리로 전달되는 상황이 아니므로, 위와 같이 셀입력값을 참조하는 상황이므로, 그렇다면 어떤 상황이라도 A1 셀에 7이 입력되는 사건이 먼저 일어나야한다는 것은 명명백백하다. (맞잖아요? 근데…) ---->
결과값 7을 도출한 이후, 이를 셀에 입력하는 시간도 엑셀은 분명히 할애해야할 것이다. 이 행위에 찰나가 걸리더라도 어차피 시간이 걸린다는 점은 분명할 것이다. (바로 여기에서 의문이 시작됨)
제가 말씀드린 셀값입력은 셀값업데이트를 의미하는 것이 아닙니다. 3 + 4 = 7 을 도출했다. 이것은 계산행위이고, 계산값으로 도출된 7 을 셀에 할당해줘서 다른 곳에서 참조가 가능하게 하는 행위. 이것을 저는 셀값입력 행위라고 정의하고 싶습니다. 제 의문의 포인트는 셀값 7이 아니라, 이 값 7을 다른곳에서 참조할 수 있게 하기까지 걸리는 시간. 이렇게 [ 속도 ] 를 정의하고 싶은 것이지요.
VBA 변수 a = 7 (메모리) → 엑셀 시트 Range("A1").Value = 7 (셀) 이 과정은 메모리 복사와 COM 인터페이스 통신이 일어나는 "실제 작업 시간"입니다. 단순히 “보여주기 위한 시간”이 아니라, 주방에서 만든 요리를 홀까지 직접 들고 나가는 것과 같아서 손님 눈에 보이든 안 보이든 “이동 시간”이 분명히 존재하는 노동입니다.선생님께서도 위에서 말씀하셨다시피 셀값입력은 엑셀의 [ 노동 ] 행위에 포함된다는 점입니다. 더 정확히 말하면 [ 시간노동 ] 이라고 해야할 겁니다. 그렇다면 이제 제 고민은 [ 다른 곳에서 이곳을 참조할 때 셀 입력전에도 참조가능할 수도 있는 상황은 어떻게 설명해야 하나 ] 라는 말도 안되는 고민이 생겨버린 겁니다. 분명히 위에서 [ 이 사건의 앞뒤정황상 분명히 셀 입력이 먼저 일어나야 한다 ] 라고 가정했는데, 이 가정이 틀려버려 결국 제가 만든 결론은 참도 아니고 거짓도 아닌 참으로 요상한 상황에 놓여버린 겁니다.
위 언급한 시간노동을 엑셀이 무시하도록 설계해놓았다면 값이 셀에 입력되기도 전에 참조가능할 수도 있다는 결론을 만들 수 있습니다. 맞잖아요? 쉽게 말해 엑셀은 7을 이미 도출했다. 그러면 이를 셀에 입력하는 노동시간을 무시한다면 바로 재계산하러 출발할 수도 있다. 셀입력이라는 노동은 셀계산값이 무엇인가에는 영향을 끼치지 않으므로 충분히 그렇게 설계되었을 수도 있다. 이게 마치 [ 광명역에 도착한 KTX 를 보고 광명역 전광판은 기차가 접근하고 있다고 안내할 때, 정작 KTX 는 광명승객도 순식간에 태워버리고 이미 대전역에 도착하여 대전승객까지도 태우고 있다 ] 는 상황과 유사하게 변해 있는 것이지요. KTX 는 스스로 매우 속력이 빠르다는 기능을 이미 가지고 있으므로, 전광판에서 뭐라고 안내하던 말던 지는 지 일을 하러(대전승객 태우러 = 재계산하러) 떠날 수 있다는 말입니다. 느린 전광판때문에 KTX가 광명역에서 정차 대기해야한다는 제한을 철도청에서는 만들어 놓지 않았겠죠. 마찬가지로 엑셀도 이렇게 설계되어 있지 않았을테구요.
제 질문이 좀 뜬금없어서 죄송합니다. 닭이 먼저냐? 알이 먼저냐? 이 문제는 앞뒤 사건의 정황을 알 수 없으므로 순환논증의 오류로 끝나버릴 수 밖에 없지만, 셀값 참조는 앞뒤 사건의 정황이 명확한데도 불구하고 순환논증의 오류로 빠져버리는 아주 황당한 경우라고 봐야하지 않을까요? 셀값입력이 먼저 되어야 한다. 그래야 참조가 가능하니까. 셀값입력이 아직 안되어 있다. 그런데 참조는 가능하다. 뭔가 앞뒤가 안맞는 이야기입니다.
이상 이 이슈는 여기까지만 하는 것이 낫겠습니다. 안그러면 엑셀질문이 추상화, 관념화되어 자못 선문답으로 흘러버릴 것 같네요. 엑셀이라는 배가 뜬금없이 산으로 향하는 상황이 나올 것 같습니다.
제가 배열을 사용할 수 없었던 이유 :
네. 저도 배열을 사용하는 것이 최상이라고 생각은 했지만 제가 맞닥뜨린 문제의 파일은 각각의 셀들이 자기만의 소소한 계산을 하고 이렇게 도출된 값들이 서로서로 동시성없이 수천, 수만 개가 있다는 사실입니다. 예를 들어 A1 셀에는
와 같은 수식이 입력되어 있다면, B1 셀에도 유사한 수식이 입력되어 있습니다. 그런데 testC, testD 등이라서 기능은 셀마다 서로 서로 다릅니다. 그런데 이런 사소한 계산을 하는 셀들이 수천, 수만 개라는 점이 제가 속도를 고민하게 된 이유인데요. 각각의 셀들에서 발생한 지연들은 시냇물처럼 모여서 나중엔 거대한 물결로 지연을 발생시키는 큰 강이 될 것이라는 걱정을 하는 것이지요. 저런 간단함수들이 셀 여기저기에 적재적소에 배치되어 있고 동시다발적으로 계산을 하고, 또한 이 계산값들을 다른곳에서 또 재참조하고, 이런 논리로 셀들끼리 서로 영향을 받기도 하고 영향을 주기도하며 쉼없이 계산하는 상황에서, 각 셀들의 계산방식을 개선하면 엑셀 전체계산 속도가 획기적으로 빨라질 것이라는 필요성이 생긴 겁니다. 이 파일에서 가장 흔한 방식이 바로 제가 질문에서 제시한 A, B 두 가지입니다. Sub 로도 해보고 Function 으로도 해보고, 급기야 될 수 있는 한 셀입력이 필요한 상황이 아니라면 변수에서 변수로 바로 계산값을 넘겨주는 방식으로 하여 셀접근 부담을 줄이기도 하였습니다.
배열도 생각해봤지만 저 수많은 셀들을 다 변수화 또는 배열화하기 위해서는 또 셀에 접근해야 하는데 이 또한 부하가 걸리는 일이라면 과연 의미가 있나? 그런 의문이 들었구요. 그러니까..
이걸 활용해보고 싶어도, 참조할 앞도출값을 셀에서 받아와야 한다면,
arrInput = Range("A1:B" & eRow).Value와 같은 상황이므로 또 셀접근부담을 져야 하잖아요. 각각의 셀들은 동시성없이 자기계산만을 수시로 하는 상황입니다. 어느 타임에 이를 수집해야하냐도 관건이지만 시시때때로 변하는 데이터를 왜 하필 이때 수집해야 하나 그것도 의문이 듭니다. 이처럼 수집비용과 신뢰도 이슈가 생기는 상황에서 굳이 배열을 이용하는 것은 의미가 없다고 봐야겠죠. 그렇게 결론내면 결국 셀단위 계산으로 넘어가서 이야기를 다시 해야합니다.
Dependency Tree(의존성 트리)에 대한 설명은 저번에 선생님께서 너무 자세히 알려주셔서 충분히 이해하고 있습니다. Function 으로 도출한 값은 고정값으로 인식하지 않고 휘발성으로 인식하여 엑셀은 늘 긴장상태를 가지고 Dependency Tree 를 재구성할 준비를 해야하니 어차피 A, B 가 3 + 4 = 7 과 같이 동일한 기능을 하는 계산이더라도 엑셀은 Function 에 대해 느끼는 피로도가 더 높다는 것으로 저는 해석하고 있습니다. 결국 엑셀이 느끼는 이 긴장감은 메모리 자원을 쓸데없이 낭비할 요인이 될 수도 있다는 걱정도 생기네요.
위 모든 의견들을 종합해보면 A, B 중 제가 선택해야 할 것은 A 라는 결론에 이르는군요. 무엇보다 엑셀은 휘발성없는 고정값을 선호한다는 메리트를 엑셀이 선택할 수 있게 해줘야할 것 같습니다. 매크로를 다시 실행해서 값들을 새로 갱신해 주는 부담은 없습니다. 질문용 예제파일에 만들었던 값입력 매크로는 제가 질문용으로 만든 것이고 실제의 파일에서 이 값들은 앞 계산에서 받아와야 하는데 그 값들은 셀에 저장되어 있고, 그것을 변수로 읽어서 저장하던지, 또는 Function 으로 도출한 자체입력된 값들이거나, 이 값들이 서로서로 유기적으로 영향을 끼치기도 하고, 영향을 받기도 하는 상태입니다. 어차피 갱신해줘야할 값들은 스스로 셀에서 갱신되고 있는 상황입니다.
선생님의 자세하고 차원높은 설명에 또 감사드립니다. 매번 주말마다 찾아뵙고 뜬금없는 질문을 드려 죄송합니다. 그리고 매번 주말마다 곧장 답변을 달아주시고 궁금증을 해소해 주셔서 감사드립니다. 엑셀에 대한 성격을 한가지 한가지 알아갈 때마다 희열을 느낄만큼 재밌습니다. 이게 다 선생님께서 너무 좋은 설명을 해주신 덕분이라고 생각합니다. 좋은 일요일 아침 되시고 늘 건강하세요. 감사합니다.
질문자님의 댓글은
단순한 기술적 문의를 넘어, "엑셀의 시간(Time)과 인과율(Causality)"에 대한
일종의 철학적 고찰에 가깝습니다. 정말 논의해 볼만한 깊이 있는 고민이 담겨있네요.
좀 정리해 보자면 보내주신 긴 글 속에는 세 가지의 거대한 고민이 담겨 있습니다.
첫번째, 순환 논증의 공포인데,
"값을 참조하려면 셀에 입력이 되어야 한다(선후관계 명확). 그런데 셀에 입력하는 행위는 "노동(시간)"이 든다. 엑셀이 아무리 빨라도 이 노동 시간을 건너뛸 수는 없을 텐데, 그렇다면 참조는 언제 일어나는가?"
"혹시 엑셀은 KTX처럼 너무 빨라서, 전광판(셀 입력)에 띄우는 노동을 무시하고(혹은 비동기적으로 처리하고) 이미 다음 계산(참조)을 수행하러 떠나는 설계를 가진 것이 아닐까?"
"만약 입력도 안 됐는데 참조가 된다면 인과율에 위배되고, 입력될 때까지 기다린다면 속도가 느려지는 진퇴양난(순환 논증)에 빠질 수 있다"
두번째, 배열(Array) 사용이 비정형성으로 현실적으로 어려울 수 있는데,
"예제처럼 단순 반복 계산이 아니라, testB, testC 등 수만 개의 셀이 서로 다른 로직으로 얽혀 있어서 비동기적이고 개별 계산을 해야 한다"
"이걸 억지로 배열로 만들려면, 어차피 셀 값을 하나하나 읽어와야(Range.Value) 하므로 "수집 비용"이 더 든다. 시냇물처럼 흐르는 개별 계산들을 억지로 댐(배열)으로 막는 것이 비효율적이다."
세번째, 그럼 최종 선택은 TestA방식으로 (Sub 방식 - 값 고정)하는 것인데,
"Function(UDF) 방식은 엑셀의 의존성 트리(Dependency Tree)를 계속 긴장 상태(휘발성 대기)로 만들어 메모리와 리소스를 낭비한다."
"차라리 매크로를 통해 계산을 끝내고 정적인 값(Static Value)을 셀에 박아버리는 TestA가 낫다. 엑셀 엔진이 해당 셀을 "더 이상 계산할 필요 없는 숫자"로 인식하게 하여 휴식을 주는 것이 전체 속도 향상에 이득이다."
위 세가지 고민에 대한 질문자님의 잠정적 결론은
"엑셀에게 "생각(Calculation Chain)"을 멈추게 하고, "기억(Static Data)"만 남기겠다."
"셀 접근 비용(Interface Cost)"이라는 페널티를 감수하더라도, "재계산 엔진의 부하(Engine Stress)"를 줄이는 것이 거시적인 관점에서 이득"이라는 전략적 판단인 거 같습니다.
여기서 일단 "'KTX 예시"에 대한 오해 하나만 바로잡아 드리고 몇가지 설명을 드리고 이번 질문에 대한 총제적인 답변과 샘플 코딩을 제안드리는 것으로 갈무리 하겠습니다.
"엑셀은 동기식(Synchronous)입니다."
질문자님의 우려대로, 셀에 값이 완전히 입력되는 노동이 끝나야만(Commit), 비로소 다음 줄의 참조가 가능합니다.
KTX가 전광판을 무시하고 떠나는 일(비동기 처리)은 VBA와 셀 사이에서는 일어나지 않습니다.
즉, "입력 노동 시간"은 반드시 소요됩니다.
그럼에도 불구하고
질문자님이 TestA 선택이 타당한 이유는
그 "입력 노동 시간"을 감수하더라도, 수만 개의 UDF가 유발하는 "상시 재계산 대기 상태의 피로도"가 훨씬 더 치명적이기 때문입니다.
즉, 복잡하게 얽힌 비정형 데이터 환경에서는 질문자님의 판단대로 TestA(값 고정) 방식이 엑셀을 가장 가볍게 만드는 최선의 선택입니다.
그럼 위 내용을 비유를 통해
엑셀 연산과정을 기술적으로 설명을 드리도록 하겠습니다.
언제나처럼
이 답글의 모든 내용은 다양한 접근방식이 있고, 질문자님의 고민에 대한 개인적으로 조그마한 도움이나마 드리는 의도이므로 기술적인 오류나 잘못된 정보가 있을 수 있음을 감안해 주시면 좋겠습니다.
“요리가 완성되고, 접시에 담아 테이블에 올려놓고, 다른 요리가 그걸 참조해서 만들어지는 이 전체 과정에서 정확히 언제 뭐가 먼저 일어나고, 왜 배열 방식은 내 실제 구조에 안 맞는지, 그래서 결국 어떤 방식(A vs B)을 쓰는 게 맞는지를 다시 정리하고 싶다.”
이제 이 비유를 바탕으로,
엑셀의 연산 메카니즘적인 측면에서 “엑셀 엔진이 참조 시점과 셀 쓰기 시점이 실제로 어떻게 동작하는지”를 조금 더 풀어보도록 하겠습니다.
“진짜 내부적으로 어떤 순서로 처리된다고 보는 게 맞는지”
즉,
"엑셀은 “값을 계산하는 순간”과 “셀에 값을 쓰는 순간”을 어떻게 처리하며,
참조는 그 과정 중 어느 시점에 가능한가?"
엑셀 엔진의 실제 처리 순서는 이렇게 보는 게 가장 정확하다고 볼 수 있습니다.
엑셀은 계산을 아래 4단계 방식으로 처리하는데,
https://learn.microsoft.com/en-us/office/client-developer/excel/excel-recalculation
https://learn.microsoft.com/en-us/office/open-xml/spreadsheet/working-with-the-calculation-chain
□ 1단계 Dependency Loading (의존성 분석 단계)입니다.
“누가 누구를 보고 있는가를 먼저 파악하는 단계”로서
엑셀은 먼저
“B1이 A1을 참조하는가?”
“C5가 B1, D8, F1을 참조하는가?”
이런 관계를 의존성 트리(Dependency Tree) 로 정리합니다.
위 비유에서 보자면, 식당의 주문서 정리라고 할 수 있고,
“어떤 요리는 다른 요리가 먼저 완성되어야 한다”
즉, “라면 + 소안심 = 소안심 먼저 구어라” 같은 순서표를 먼저 만드는 단계로 볼 수 있습니다. 그러나 이 단계에서는 아직 아무 계산도 안 합니다.
□ 2단계 Execution Scheduling (계산 순서 결정 단계)입니다.
“이제 어떤 셀부터 계산할지를 정한다.”
순환 참조가 없는 경우(되돌아가는 루프가 없는 경우)에 DAG(Directed Acyclic Graph) Topological sorting을 사용합니다.
즉, 먼저 계산해야 하는 셀 → 그걸 사용하는 셀 → 그걸 또 쓰는 셀을 결정하는데,
위 비유에서 보자면, 주문에 따른 요리 동선을 설계합니다.
“프라이팬 → 소안심 → 냄비 → 육수 → 재료 → 가열 → 서빙”
이러한 순서표를 확정하지만 이 단계도 역시 아직은 셀에 값을 쓰지 않습니다.
□ 3단계 Calculation Phase (실제 계산 단계)입니다.
“메모리에서 값 계산”
여기서 중요한 핵심은 엑셀은 셀을 계산할 때 셀에 바로 쓰지 않습니다.
먼저 메모리 버퍼(Buffer, Calc Cache) 에 값을 저장합니다.
즉, Result = 3 + 4 → Value = 7
이 연산과 결과값은 아직도 메모리에 존재합니다.
위 비유에서 보자면, 요리는 접시가 담긴 있는 상태가 아니라, 아직 주방 조리대에서 대기 중인 상태로
매우 중요한 지점인데,
이 시점에서 이미 다른 계산에서 이 값을 참조할 수 있습니다.
그래서 결론적으로
“엑셀은 내부에서는 “계산 → 참조 → 쓰기”가 분리되어 다른 계산에서 참조할 수 있지만, VBA에서는 반드시 “쓰기 → 참조” 순서를 따라야 한다.“
는 관점이 나오며, 아마도 질문자이 느끼던 "모순"이 여기서 풀릴지도 모릅니다.
□ 4단계 Commit & Render (셀 값 쓰기와 화면 업데이트)입니다.
“이제 계산된 값을 시트에 기록하고, 화면에 보여준다”
여기서 두 가지 갈래가 발생하는데,
Calculation 이후 Commit(셀에 실제 값 기록)는 메모리에서 Sheet Object Model로 값이 이동하고,
Commit(셀에 실제 값 기록) 이후 필요에 따라 Render(눈으로 보이는 갱신)는 화면 갱신(ScreenUpdate)을 진행합니다.
위 비유에서 보자면, Commit은 셰프가 접시를 테이블에 놓는 행위이고, Render는 손님이 그 접시를 보는 순간을 의미하는데, 여기서 속도 차가 생깁니다.
Calculation(계산)은 CPU, 메모리와 내부 작업으로 매우 빠릅니다.
반면에 Commit(셀 접근)은 COM 오브젝트, 인터페이스 전환 비용으로 느리고
Render는 옵션으로 보이지 않아도 계산은 됩니다.
따라서 아주 중요한 결론인데
공식 문서와 계산 체인 구조를 종합하면,
실제 엔진 내부에서는 “계산(메모리 버퍼) → 참조 → 셀 기록”이 분리되어 있을 가능성이 매우 높습니다.
그래서 “참조는 셀에 보이는 시점과는 독립적으로 일어난다”고 이해하는 것이
모순 없이 설명하는데 가장 자연스럽습니다.
왜 엑셀은 이런 구조를 가질까요?
이 방식 덕분에 엑셀은
수천~수십만 셀을 계산하더라도 Sheet Object 접근(가장 느린 작업)을 최소화할 수 있습니다.
최종적으로 아래 단계로 정리할 수 있는데,
① 의존성트리 분석으로 주문서 정리처럼 어떤 셀의 값이 다른 셀에 필요한지 분석하고
② 계산 스케줄링를 통해 요리 순서를 확정합니다.
③ 메모리에서 값을 계산하여 요리가 트레이 쌓이듯이 버퍼에 저장합니다.
④ Commit함으로써 트레이를 테이블에 내려놓듯이 셀에 값을 저장합니다.
⑤ Rendering을 통해 화면을 갱신(옵션)함으로 손님이 음식을 볼 수 있게 합니다.
아울러, 손님이 보기 전에도
주방은 이미 그 요리를 이용해 다음 메뉴를 만들 수 있습니다.
즉, 참조는 셀 값이 보이기 전에 이미 가능하다는 것입니다.
댓글을 마무리하며,
아래와 같은 업무프로세스를 권해드립니다.
먼저, UDF를 “셀에서 호출되는 함수”가 아니라
VBA 엔진에서만 쓰는 내부 함수로 바꿉니다.
이제 시트에 있는 =testB(...) 수식들은 지워버리고,
대신 “버튼 눌렀을 때 한 번에 계산”하게 만듭니다.
두 번째, 엔진 메인을 코딩하는데,
이 프로시저는 전체 재계산 버튼입니다.
세 번째, 기존의 testB가 담당하던 영역을 통으로 계산하는 블록을 코딩합니다.
Private Sub Block_TestB() Dim ws As Worksheet Dim eRow As Long, i As Long Dim arrIn As Variant Dim arrOut As Variant Set ws = ThisWorkbook.Sheets("Data") '// 실제 시트명으로 변경 '// testB가 원래 적용되던 행 범위 eRow = ws.Cells(ws.Rows.Count, "B").End(xlUp).Row '// 1) 입력 (B열, C열) 한 번에 읽기 arrIn = ws.Range("B2:C" & eRow).Value '// 2) 출력 카트 준비 (A열에 쓸 예정) ReDim arrOut(1 To UBound(arrIn, 1), 1 To 1) '// 3) 메모리에서 한 줄씩 F_TestB 로 계산 For i = 1 To UBound(arrIn, 1) arrOut(i, 1) = F_TestB(arrIn(i, 1), arrIn(i, 2)) Next i '// 4) 결과를 A열에 한 번에 써주기 ws.Range("A2").Resize(UBound(arrOut, 1), 1).Value = arrOut End Sub이러한 튜닝은
예전에 시트에 =testB(...)가 10,000개 있어서
재계산할 때마다 10,000번 UDF 호출하지만
지금은 시트에는 값만 있고
Engine_RecalcAll 누를 때만 10,000건을 배열로 한 번에 계산 후, 한 번에 쓰도록 하게 합니다.
이러한 관점은,
“UDF인 testB의 로직을 꺼내서,
testA+ 타입(배열 + Sub 기반 엔진)으로 최적화했다.”고 볼 수 있습니다.
전체 수식의 계산 체인이 어떻게 이루어진 것이냐에 따라 다를 것 같습니다.
계산이 기존 자료를 한 번에 받아서 VBA가 메모리에서만 계산하고 마지막에 한 번에 돌려주는 방식이면, 전체를 VBA로 하는 게 좋겠지만,
기존 자료를 받아서 계산을 하고, 시트에 기재하고 이어서 Excel이 계산을 진행하고, 다시 VBA가 계산된 결과를 받아서 다음 처리를 해야 하는 구조라면 Excel의 내장 수식을 사용하도록 하는 게 더 좋을 것 같습니다.
예시가, VBA에서의 계산과 Cell에 UDF로 사용할 때의 계산이라면, 당연히 VBA 일관 계산이 빠르겠지요.
전체 계산과정을 하나의 flow로 정리해 보세요.
표처럼 정규화 되지 않는 자료에서 계산로직을 일괄 적용하는 방식은 UDF가 더 나을 듯 하고,
정규화 된 자료라면 배열로 읽어서 VBA로 일괄 처리해 주는 방식이 좋을 듯 합니다.
위의 다른 대댓글에 쓰신 것처럼 시트읽기 -> VBA계산 -> 시트쓰기 -> 다시읽기 -> 다른계산 -> 시트쓰기 ... 이런 구조라고 하더라고, 읽어와야 할 곳이 규칙상 명확하다면 중간에 시트에 쓰지 않고 모두 배열로 계산하는 방법으로 하시면 됩니다.
다행히 VBA가 배열을 임의로 1을 base로 쓸수 있어서, Cell주소와 거의 같은 배열을 만들 수 있으므로,
심한 경우는 필요한 시트를 Arr1, Arr2, Arr3 ...배열에 몽땅 읽어와서, 필요한 계산을 한 다음 다시 모든 시트로 돌려주는 방식도 어렵지 않게 사용할 수 있습니다.
대량 작업일 경우 최선은 시트읽기와 시트쓰기가 가장 적은 것이 좋습니다.
선생님 안녕하세요.
네. 제가 처한 상황은....
과 같습니다. VBA로 일괄처리하고 싶어도 셀들마다 계산방식과 값들이 별개라서 사정상 여의치 못한 측면이 있습니다. 그래서 결국 셀수식으로 해결할 때 어떤 방식이 더 유리할까 그것을 궁리하게 된 이유이고요. 간혹 VBA로 부분 일괄처리해야할 곳들은 또 그 방식에 맞게 처리하게끔 합니다. 그런데 자꾸 모자람을 느끼니 무엇이 더 빠른 방식인가에 대한 고민을 하게 됐습니다.
제가 차후에 정말 질문하고 싶었던 것이 바로 이거인데요. 아직은 이르다고 판단되어 이 질문을 못드리고 있는 상태입니다. 좋은 답변을 얻을려면 의도가 명확한 예제파일도 만들어야 하고 질문을 잘하는 것도 간단치 않은 문제가 있잖아요. 제가 차후에라도 궁극적으로 질문하고 싶은 것에 대해 지금 미리 몇마디로 요약하면 [ 속도향상을 위하여, 극단적으로 단 1번도 셀접근없이, 모든 값들을 메모리에서 메모리상으로만 저장/참조/이동 시키며 계산체인을 구성하는 방법은 무엇인가 ] 라는 점인데요. 그것이 구현된다면 엑셀을 열 때 아래와 같이 될 겁니다.
네. 빈 공백뿐입니다. 그러나 무대 뒤 VBA상에서는 열심히 일을 하고 있겠죠.
저는 계산 도중의 시각화를 필요로 하지 않습니다. 결과값만 잘 도출하면 되잖아요. 그 수천 개의 셀들에 무슨 값이 생겼다 사라지고, 그 다음 계산을 수행하러 갈 때 또 무엇이 입력되어 있냐를 따지는 것도 눈으로 확인하는 건 무의미합니다. 대부분의 엑셀파일들이 그렇잖아요. 그 과정을 인간의 눈으로 읽지도 못하지만 읽을 필요도 없잖아요. 그런데 문제는 [ 계산값들에 대한 시각화는 필요없다해도, 계산로직 구현시 도중의 값들이 어느정도는 시각화되어야 그것을 어디에서 참조해야할 지를 즉흥적으로 알게 되잖아요. A1셀을 B1셀에서 참조하고, 그 결과값을 또 C1셀에서 참조하고, 이런 로직이 수백개 있을 때, 셀 그 자체가 지도가 되어 우리는 그 주소를 찍어주기만 하면 되는데, 이걸 메모리상에서 변수에서 변수로만 저장/참조/이동 시킨다면, 지도가 없기 때문에 마치 국어사전 찾듯이 수백개 변수명을 찾아서 작업을 해야하잖아요. 국어사전은 시각화된 지도가 아니라는 점이 우리 뇌를 힘들게 만들구요. 바로 이점 때문에 결국 시각화할 것은 시각화하면서 계산로직을 짤 수 밖에 없을 것이다 ] 라고 느낍니다.
그래서 제가 곰곰 생각했던 점이 [ 아마 저와 같은 빈공백 페이지(오직 VBA상 계산만 있는 페이지) 를 만들고 싶어하는 사람이 분명 있을 것이다. 시각화는 건너뛰어버리구요. 그렇다면 그걸 한방에 변환시켜주는 앱이 있지 않을까? ] 그런 생각도 해봤습니다. 이름을 짓는다면 [ 엑셀계산로직 VBA 시각화도구 ] 또는 [ 엑셀 셀주소를 변수화/배열화시키는 도구 ] 쯤 될려나요. 분명 이런 것이 필요했던 사람이 있었을 것이고, 그렇다면 이 필요는 실제로 이걸 앱으로 짠 사람이 있을 것이라는 예상입니다. 혹시 정말 있을까요?
예: 문자열 [ 엑샐 ] 을 [ 엑셀 ] 로 치환하는 것은 어렵지 않습니다. 인간은 이 작업을 하는 것이 힘들지만 앱은 한방에 끝냅니다. 마찬가지로 각각의 셀 주소를 배열화된 주소 A1 = Arr(1.1) 로 한방에 치환시켜 버려 종국에는 셀수식이 단 1개도 없고 VBA 상에서만 변수/배열/메모리상에서만 계산이 이루어지게, 이처럼 VBA 코딩화시켜주는 앱이 분명히 어딘가에는 있을 것 같은데요.
답글달아주셔서 감사드립니다. 편안한 일요일 저녁 보내세요. 감사합니다.
구체적으로 어떤 걸 말씀하시는 지 잘 이해가 가지 않습니다만,
제가 업무에서 사용하도록 만들어 놓은 일자별 생산계획 시물레이션 기능을 예로 들면,
시트 하나에 라인/설비별 근무달력( 날짜별/라인별/근무시간)을 작성하고,
다른 시트에 라인/제품별 기본 UPH, 표준 기종변경시간을,
다른 시트에 특정 라인에 기본 UPH가 적용되지 않는 특별 모델의 UPH,
메인 시트에 생산 LOT별 생산 계획(잔)량과 작업할 순서,
이렇게 기본 데이터를 준비한 다음에,
하나의 매크로로 라인별로 LOT별로 생산시작일자부터 근무 달력에 따라 일자별로 몇 개씩을 생산 계획으로 할당하는지 순서대로 차근차근 계산해서 여러 조건에 따라 계산한 다음, 시작일자~종료일자, 일자별 생산 할당량의 데이터 표를 최종적으로 한 번에 출력하도록 하고 있습니다.
중간에 자잘한 계산들도 모두 VBA의 배열을 통해서 진행하기 때문에 사용자는 그 내용을 볼 필요가 없고, 성공한 경우 계산된 결과나 조건 계산시 데이터 오류 내용만 출력해주는 매크로를 사용하고 있습니다.
말씀중에 중간에 셀 계산을 해야 하고 -> VBA에서 하셔도 됩니다.
셀값을 변수로 사용... -> 배열의 주소를 셀 주소처럼 사용하면 됩니다.
(예, Cells(5,3).Value2 -> Arr1(5,3) )
배열의 값을 그대로 사용할 지, 계산을 위해서 변수에 할당할 지는 매크로 구성에 맞게 선택하시면 됩니다.