> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 빠른 시작 둘러보기

> ClickHouse를 빠르게 시작할 수 있는 빠른 시작 가이드를 살펴보세요

export const quickStartsData = [{
  "id": "connect-your-iceberg-catalog",
  "title": "ClickHouse Cloud에서 Iceberg 카탈로그를 연결하는 방법",
  "description": "ClickHouse Cloud를 데이터 카탈로그에 연결하고 Iceberg 테이블을 쿼리하는 방법을 알아봅니다.",
  "href": "/ko/get-started/quickstarts/connect-your-iceberg-catalog",
  "useCases": ["data-warehousing"],
  "products": ["cloud"]
}, {
  "id": "create-your-first-materialized-view",
  "title": "첫 materialized view 만들기",
  "description": "ClickHouse에서 materialized view를 사용해 쿼리 결과를 다른 정렬 순서로 미리 계산해 저장하고, 프라이머리 키(primary key)에 포함되지 않은 컬럼에서도 빠르게 조회하는 방법을 알아봅니다.",
  "href": "/ko/get-started/quickstarts/create-your-first-materialized-view",
  "useCases": ["real-time-analytics", "data-warehousing"],
  "products": ["cloud"]
}, {
  "id": "create-your-first-mergetree-table",
  "title": "첫 번째 MergeTree 테이블 만들기",
  "description": "MergeTree 테이블을 만들고 영국 부동산 가격 데이터를 불러오면서, 파트와 머지가 저장소와 쿼리 성능에 어떤 영향을 미치는지 관찰해 ClickHouse의 주요 테이블 엔진이 어떻게 작동하는지 알아봅니다.",
  "href": "/ko/get-started/quickstarts/create-your-first-mergetree-table",
  "useCases": ["all"],
  "products": ["cloud"]
}, {
  "id": "create-your-first-projection",
  "title": "첫 번째 프로젝션 만들기",
  "description": "ClickHouse에서 프로젝션을 사용해 동일한 테이블 내에 정렬된 데이터 사본을 추가로 저장하고, 프라이머리 키(primary key)에 포함되지 않은 컬럼도 빠르게 조회하는 방법을 알아봅니다.",
  "href": "/ko/get-started/quickstarts/create-your-first-projection",
  "useCases": ["real-time-analytics", "data-warehousing"],
  "products": ["cloud"]
}, {
  "id": "create-your-first-service-on-cloud",
  "title": "첫 번째 Cloud 서비스를 만들고 예시 데이터 불러오기",
  "description": "ClickHouse Cloud 서비스를 만들고 SQL 콘솔을 살펴본 뒤 예시 데이터셋을 로드하여 몇 분 만에 실제 데이터에 쿼리를 실행할 수 있습니다.",
  "href": "/ko/get-started/quickstarts/create-your-first-service-on-cloud",
  "useCases": ["all"],
  "products": ["cloud"]
}, {
  "id": "creating-tables",
  "title": "ClickHouse에서 테이블 생성",
  "description": "ClickHouse에서 테이블 생성에 대해 알아봅니다",
  "href": "/ko/get-started/quickstarts/creating-tables",
  "useCases": ["all"],
  "products": ["self-managed"]
}, {
  "id": "insert-data-using-clickhouse-client",
  "title": "clickhouse-client로 ClickHouse Cloud에 데이터 삽입",
  "description": "명령줄에서 clickhouse-client를 사용하여 로컬 CSV 및 Parquet 파일의 데이터를 ClickHouse Cloud 서비스에 삽입하는 방법을 알아봅니다.",
  "href": "/ko/get-started/quickstarts/insert-data-using-clickhouse-client",
  "useCases": ["all"],
  "products": ["cloud"]
}, {
  "id": "mutations",
  "title": "ClickHouse 데이터 업데이트 및 삭제",
  "description": "ClickHouse에서 업데이트 및 삭제 작업을 수행하는 방법을 설명합니다",
  "href": "/ko/get-started/quickstarts/mutations",
  "useCases": ["data-warehousing"],
  "products": ["self-managed"]
}, {
  "id": "obtain-your-cloud-connection-details",
  "title": "Cloud 연결 정보 확인",
  "description": "외부 클라이언트, CLI, 애플리케이션에서 연결할 수 있도록 ClickHouse Cloud 서비스의 호스트명, 포트, 자격 증명을 확인하는 방법을 알아봅니다.",
  "href": "/ko/get-started/quickstarts/obtain-your-cloud-connection-details",
  "useCases": ["all"],
  "products": ["cloud"]
}, {
  "id": "working-with-the-map-type",
  "title": "ClickHouse에서 맵 타입 사용하기",
  "description": "OTel 리소스 속성을 예시로, ClickHouse에서 동적 키-값 데이터를 저장, 쿼리, 집계하는 데 맵 타입을 사용하는 방법을 알아봅니다.",
  "href": "/ko/get-started/quickstarts/working-with-the-map-type",
  "useCases": ["observability"],
  "products": ["self-managed"]
}, {
  "id": "writing-queries",
  "title": "ClickHouse 데이터 선택",
  "description": "ClickHouse 데이터 선택에 대해 알아봅니다",
  "href": "/ko/get-started/quickstarts/writing-queries",
  "useCases": ["all"],
  "products": ["self-managed"]
}];

export const QuickStartsGrid = ({quickStartsData = [], featured = []}) => {
  const featuredIds = featured.map(f => f.id);
  const data = quickStartsData || [];
  const assetBase = typeof window !== "undefined" && window.location.pathname.startsWith("/docs") ? "/docs" : "";
  const withBase = p => p && p.startsWith("/") ? assetBase + p : p;
  const useCaseOptions = [{
    value: "real-time-analytics",
    label: "실시간 분석"
  }, {
    value: "data-warehousing",
    label: "데이터 웨어하우징"
  }, {
    value: "observability",
    label: "관측성"
  }, {
    value: "ai-ml",
    label: "AI/ML"
  }];
  const productOptions = [{
    value: "self-managed",
    label: "ClickHouse (Open-Source)"
  }, {
    value: "cloud",
    label: "ClickHouse Cloud"
  }, {
    value: "clickpipes",
    label: "ClickPipes"
  }, {
    value: "language-clients",
    label: "언어 클라이언트"
  }, {
    value: "clickstack",
    label: "ClickStack"
  }, {
    value: "chdb",
    label: "chDB"
  }];
  const explorable = data.filter(qs => !featuredIds.includes(qs.id));
  const visibleUseCaseOptions = useCaseOptions.filter(o => explorable.some(qs => {
    const u = qs.useCases || [];
    return u.includes("all") || u.includes(o.value);
  }));
  const visibleProductOptions = productOptions.filter(o => explorable.some(qs => (qs.products || []).includes(o.value)));
  const readStored = key => {
    if (typeof window === "undefined") return null;
    try {
      return localStorage.getItem(key);
    } catch {
      return null;
    }
  };
  const writeStored = (key, value) => {
    if (typeof window === "undefined") return;
    try {
      localStorage.setItem(key, value);
    } catch {}
  };
  const readStoredSelection = (key, options) => {
    const raw = readStored(key);
    if (!raw) return [];
    try {
      const parsed = JSON.parse(raw);
      if (!Array.isArray(parsed)) return [];
      return parsed.filter(v => options.some(o => o.value === v));
    } catch {
      return [];
    }
  };
  const [searchTerm, setSearchTerm] = useState(() => readStored("quickstarts-search") || "");
  const [selectedUseCases, setSelectedUseCases] = useState(() => readStoredSelection("quickstarts-usecases", visibleUseCaseOptions));
  const [selectedProducts, setSelectedProducts] = useState(() => readStoredSelection("quickstarts-products", visibleProductOptions));
  const [currentPage, setCurrentPage] = useState(1);
  const itemsPerPage = 6;
  const [showFilters, setShowFilters] = useState(() => readStored("quickstarts-show-filters") !== "false");
  const [isDesktop, setIsDesktop] = useState(true);
  useEffect(() => {
    if (typeof window === "undefined" || !window.matchMedia) return;
    const mq = window.matchMedia("(min-width: 1024px)");
    const update = () => setIsDesktop(mq.matches);
    update();
    mq.addEventListener("change", update);
    return () => mq.removeEventListener("change", update);
  }, []);
  useEffect(() => {
    writeStored("quickstarts-search", searchTerm);
  }, [searchTerm]);
  useEffect(() => {
    writeStored("quickstarts-usecases", JSON.stringify(selectedUseCases));
  }, [selectedUseCases]);
  useEffect(() => {
    writeStored("quickstarts-products", JSON.stringify(selectedProducts));
  }, [selectedProducts]);
  useEffect(() => {
    writeStored("quickstarts-show-filters", String(showFilters));
  }, [showFilters]);
  useEffect(() => {
    setCurrentPage(1);
  }, [searchTerm, selectedUseCases, selectedProducts]);
  const makeToggle = setter => value => {
    setter(prev => prev.includes(value) ? prev.filter(v => v !== value) : [...prev, value]);
  };
  const toggleUseCase = makeToggle(setSelectedUseCases);
  const toggleProduct = makeToggle(setSelectedProducts);
  const resetFilters = () => {
    setSearchTerm("");
    setSelectedUseCases([]);
    setSelectedProducts([]);
  };
  const hasActiveFilters = searchTerm !== "" || selectedUseCases.length > 0 || selectedProducts.length > 0;
  const filteredQuickStarts = useMemo(() => {
    const term = searchTerm.toLowerCase();
    return data.filter(quickStart => {
      if (featuredIds.includes(quickStart.id)) return false;
      const matchesSearch = term === "" || quickStart.title.toLowerCase().includes(term) || (quickStart.description || "").toLowerCase().includes(term);
      const useCases = quickStart.useCases || [];
      const matchesUseCases = selectedUseCases.length === 0 || useCases.includes("all") || useCases.some(uc => selectedUseCases.includes(uc));
      const products = quickStart.products || [];
      const matchesProducts = selectedProducts.length === 0 || products.some(p => selectedProducts.includes(p));
      return matchesSearch && matchesUseCases && matchesProducts;
    });
  }, [data, searchTerm, selectedUseCases, selectedProducts, featuredIds]);
  const handleCardClick = (e, href) => {
    if (e.defaultPrevented) return;
    if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0) return;
    e.preventDefault();
    window.location.assign(withBase(href));
  };
  const featuredQuickStarts = featured.map(f => {
    const qs = data.find(q => q.id === f.id);
    return {
      id: f.id,
      href: qs && qs.href || `/ko/get-started/quickstarts/${f.id}`,
      title: qs && qs.title || ""
    };
  }).filter(f => f.title);
  const FilterGroup = ({label, options, selectedOptions, onToggle}) => {
    const activeCount = selectedOptions.length;
    const displayLabel = activeCount > 0 ? `${label} (${activeCount})` : label;
    return <div style={{
      minWidth: "160px"
    }}>
        <div className="text-sm font-semibold text-black dark:text-white" style={{
      padding: "4px 0"
    }}>
          {displayLabel}
        </div>
        <div className="mt-1">
          {options.map(option => <label key={option.value} className="flex items-center gap-2 py-1.5 cursor-pointer transition-colors" onClick={e => {
      e.preventDefault();
      onToggle(option.value);
    }}>
              <span className="flex items-center justify-center w-4 h-4 rounded border flex-shrink-0" style={{
      borderColor: selectedOptions.includes(option.value) ? "#FAFF69" : "rgba(156, 163, 175, 0.6)",
      backgroundColor: selectedOptions.includes(option.value) ? "#FAFF69" : "transparent"
    }}>
                {selectedOptions.includes(option.value) && <svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
                    <path d="M2 5L4 7L8 3" stroke="black" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
                  </svg>}
              </span>
              <span className="text-sm text-black dark:text-white">{option.label}</span>
            </label>)}
        </div>
      </div>;
  };
  return <>
      <div style={{
    maxWidth: "1312px",
    marginLeft: "max(0px, calc((100vw - 1312px) / 2 - 19rem))",
    marginRight: "auto",
    paddingLeft: "1.75rem",
    paddingRight: "1.75rem"
  }}>
        <div className="my-8">
          {}
          {featuredQuickStarts.length > 0 && <div className="mb-12">
              <h2 className="text-2xl font-semibold text-gray-900 dark:text-zinc-50 mb-6">추천 빠른 시작</h2>
              <div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-6">
                {featuredQuickStarts.map(quickStart => <a key={quickStart.id} href={quickStart.href} onClick={e => handleCardClick(e, quickStart.href)} className="group block rounded-xl overflow-hidden border border-gray-200 dark:border-white/10 transition-all hover:border-black dark:hover:border-[#FAFF69] hover:shadow-md">
                    {}
                    <div className="relative w-full aspect-[2/1] overflow-hidden bg-[#FAFF69] flex flex-col justify-center px-6 pb-12">
                      <span className="relative z-10 mx-auto max-w-[90%] text-center text-base font-bold leading-tight text-black line-clamp-4">{quickStart.title}</span>
                      <div className="absolute inset-x-0 bottom-0 h-12 bg-[#E7EA5B] flex items-center justify-between px-5">
                        <img src={withBase("/images/clickhouse.svg")} alt="" aria-hidden="true" className="h-[18px] w-auto" style={{
    borderRadius: 0,
    filter: "brightness(0)"
  }} />
                        <span className="text-sm font-medium text-black">시작하기</span>
                      </div>
                    </div>
                  </a>)}
              </div>
            </div>}

          {}
          <div className="flex flex-col lg:flex-row gap-8">
            {}
            <div className={isDesktop ? "flex-shrink-0 transition-[width] duration-300 ease-in-out" : "w-full"} style={isDesktop ? {
    width: showFilters ? "16rem" : "0px"
  } : undefined}>
              <div className="lg:sticky relative" style={isDesktop ? {
    top: "8.5rem"
  } : undefined}>
                {}
                <div aria-hidden="true" className="absolute bg-gray-200 dark:bg-white/10" style={isDesktop ? {
    left: "100%",
    top: 0,
    bottom: 0,
    width: "1px"
  } : {
    top: "100%",
    left: 0,
    right: 0,
    height: "1px"
  }} />
                {}
                <button onClick={() => setShowFilters(prev => !prev)} aria-label={showFilters ? "Hide filters" : "Show filters"} title={showFilters ? "Hide filters" : "Show filters"} className="flex items-center justify-center absolute z-20 cursor-pointer rounded-full border transition-colors border-gray-300 dark:border-white/20 hover:border-black dark:hover:border-[#FAFF69] bg-white dark:bg-[#1B1B18] text-gray-500 dark:text-gray-400 hover:text-black dark:hover:text-[#FAFF69] shadow-sm" style={isDesktop ? {
    left: "100%",
    top: "50%",
    width: "28px",
    height: "28px",
    transform: "translate(-50%, -50%)"
  } : {
    top: "100%",
    left: "50%",
    width: "28px",
    height: "28px",
    transform: "translate(-50%, -50%)"
  }}>
                  <svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg" className="transition-transform duration-300" style={{
    transform: `rotate(${isDesktop ? showFilters ? 0 : 180 : showFilters ? 90 : -90}deg)`
  }}>
                    <path d="M7.5 2.5L4 6L7.5 9.5" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
                  </svg>
                </button>

                {}
                <div className="overflow-hidden transition-all duration-300" style={isDesktop ? {
    width: "16rem",
    paddingRight: "1.5rem",
    opacity: showFilters ? 1 : 0,
    pointerEvents: showFilters ? "auto" : "none"
  } : {
    width: "100%",
    maxHeight: showFilters ? "1500px" : "0px",
    paddingBottom: showFilters ? "1.5rem" : "0px",
    opacity: showFilters ? 1 : 0,
    pointerEvents: showFilters ? "auto" : "none"
  }}>
                  <div className="space-y-6">
                    {}
                    <div>
                      <label className="block text-sm font-semibold text-gray-900 dark:text-zinc-50 mb-3">검색</label>
                      <div className="relative w-full">
                        <svg className="absolute pointer-events-none z-10" style={{
    left: "12px",
    top: "50%",
    transform: "translateY(-50%)",
    width: "16px",
    height: "16px",
    color: "#666"
  }} fill="none" stroke="currentColor" viewBox="0 0 24 24">
                          <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
                        </svg>
                        <input type="text" placeholder="빠른 시작 검색..." value={searchTerm} onChange={e => setSearchTerm(e.target.value)} className="w-full text-sm border rounded-xl focus:outline-none bg-white dark:bg-[#1B1B18] text-black dark:text-white border-gray-300 dark:border-gray-600 focus:border-black dark:focus:border-[#FAFF69]" style={{
    height: "42px",
    padding: "0.5rem 0.75rem 0.5rem 2.75rem",
    lineHeight: "1.4",
    boxSizing: "border-box"
  }} />
                      </div>
                    </div>

                    {}
                    <div>
                      <div className="space-y-5">
                        <FilterGroup label="사용 사례" options={visibleUseCaseOptions} selectedOptions={selectedUseCases} onToggle={toggleUseCase} />
                        <FilterGroup label="제품 영역" options={visibleProductOptions} selectedOptions={selectedProducts} onToggle={toggleProduct} />
                      </div>
                    </div>

                    {}
                    {hasActiveFilters && <button onClick={resetFilters} className="w-full text-sm font-medium px-4 py-2 rounded-lg transition-all cursor-pointer border border-gray-300 dark:border-white/20 hover:border-black dark:hover:border-[#FAFF69] bg-white dark:bg-[#1B1B18] text-black dark:text-white">
                        필터 초기화
                      </button>}
                  </div>
                </div>
              </div>
            </div>

            {}
            <div className="flex-1 min-w-0">
              <h2 className="text-2xl font-semibold text-gray-900 dark:text-zinc-50 mb-6">빠른 시작 탐색</h2>

              {filteredQuickStarts.length > 0 ? <>
                  <div className="flex flex-col gap-2">
                    {filteredQuickStarts.slice((currentPage - 1) * itemsPerPage, currentPage * itemsPerPage).map(quickStart => <a key={quickStart.id} href={quickStart.href} onClick={e => handleCardClick(e, quickStart.href)} className="group block rounded-lg border px-4 py-3 transition-all border-gray-200 dark:border-white/10 hover:border-black dark:hover:border-[#FAFF69] bg-white dark:bg-[#1B1B18]">
                        <div className="text-sm font-semibold text-gray-900 dark:text-zinc-50">{quickStart.title}</div>
                        <div className="text-sm text-gray-600 dark:text-gray-400 mt-0.5 line-clamp-2">{quickStart.description}</div>
                      </a>)}
                  </div>
                  {}
                  {(() => {
    const totalPages = Math.ceil(filteredQuickStarts.length / itemsPerPage);
    if (totalPages <= 1) return null;
    const hasPrev = currentPage > 1;
    const hasNext = currentPage < totalPages;
    return <div className="flex items-center justify-center gap-3 mt-8">
                        <button onClick={() => hasPrev && setCurrentPage(prev => prev - 1)} disabled={!hasPrev} className={`p-2 rounded-lg border transition-all ${hasPrev ? "border-gray-300 dark:border-white/20 bg-white dark:bg-[#1B1B18] text-black dark:text-white hover:border-[#FAFF69] cursor-pointer" : "border-gray-200 dark:border-white/10 bg-gray-50 dark:bg-[#1B1B18]/50 text-gray-300 dark:text-white/20 cursor-not-allowed"}`} aria-label="이전 페이지">
                          <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                            <path d="M10 12L6 8L10 4" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
                          </svg>
                        </button>
                        <span className="text-sm text-gray-600 dark:text-gray-400">
                          {currentPage} / {totalPages} 페이지
                        </span>
                        <button onClick={() => hasNext && setCurrentPage(prev => prev + 1)} disabled={!hasNext} className={`p-2 rounded-lg border transition-all ${hasNext ? "border-gray-300 dark:border-white/20 bg-white dark:bg-[#1B1B18] text-black dark:text-white hover:border-[#FAFF69] cursor-pointer" : "border-gray-200 dark:border-white/10 bg-gray-50 dark:bg-[#1B1B18]/50 text-gray-300 dark:text-white/20 cursor-not-allowed"}`} aria-label="다음 페이지">
                          <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                            <path d="M6 4L10 8L6 12" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
                          </svg>
                        </button>
                      </div>;
  })()}
                </> : <div className="text-center py-12 flex flex-col items-center">
                  <p className="text-gray-600 dark:text-gray-400 text-lg block">검색 조건에 맞는 빠른 시작 가이드가 없습니다.</p>
                  <p className="text-gray-500 dark:text-gray-500 text-sm mt-2 block">필터 또는 검색어를 조정하여 다시 시도해 보십시오.</p>
                </div>}
            </div>
          </div>
        </div>
      </div>
    </>;
};

export const featuredQuickstarts = [{
  id: 'create-your-first-service-on-cloud'
}, {
  id: 'insert-data-using-clickhouse-client'
}, {
  id: 'obtain-your-cloud-connection-details'
}];

<div className="relative overflow-hidden">
  <div className="absolute top-0 left-0 right-0 opacity-80">
    <img src="https://mintcdn.com/private-7c7dfe99/uSvkmCa0LYc4LYQN/images/background-light.svg?fit=max&auto=format&n=uSvkmCa0LYc4LYQN&q=85&s=424518352cda5e544ec543281e4fa3b8" className="block dark:hidden pointer-events-none w-full h-auto" alt="장식용 배경 이미지." width="1152" height="388" data-path="images/background-light.svg" />

    <img src="https://mintcdn.com/private-7c7dfe99/uSvkmCa0LYc4LYQN/images/background-dark.svg?fit=max&auto=format&n=uSvkmCa0LYc4LYQN&q=85&s=5aaf0ce64be2caa4b029e88a5d639035" className="hidden dark:block pointer-events-none w-full h-auto" alt="장식용 배경 이미지." width="1152" height="388" data-path="images/background-dark.svg" />
  </div>

  <QuickStartsGrid quickStartsData={quickStartsData} featured={featuredQuickstarts} />
</div>
