데이터 베이스 MySQL 튜토리얼 复合索引创建案例分享-索引的access和filter(一)

复合索引创建案例分享-索引的access和filter(一)

Jun 07, 2016 pm 04:40 PM
access filter 공유하다 만들다 좋은 사례 색인

好久没写blog了,确实刚来南京才一个多月,新的工作也需要慢慢适应,学习脚步因此也确实放慢了很多,虽然不见得以后一直做技术,但是如果能做一天就当认真对待,言归正传,有个sql语句因为走全表扫描的执行计划需要优化,具体如下: SELECT OID, SUBSID FROM

好久没写blog了,确实刚来南京才一个多月,新的工作也需要慢慢适应,学习脚步因此也确实放慢了很多,虽然不见得以后一直做技术,但是如果能做一天就当认真对待,言归正传,有个sql语句因为走全表扫描的执行计划需要优化,具体如下:

SELECT OID, SUBSID
FROM SUBS_SERVICE A
WHERE SERVICEID IN (:SERVICEID1, :SERVICEID2, :SERVICEID3)
     AND ENDDATE      AND ENDDATE >= SYSDATE - 395
     AND REGION = 23
     AND STATUS 8
     AND STATUS 9
     AND NOT EXISTS (SELECT 1
          FROM SUBS_SERVICE B
          WHERE B.REGION = A.REGION
               AND B.SUBSID = A.SUBSID
               AND B.SERVICEID IN (:SERVICEID1, :SERVICEID2, :SERVICEID3)
               AND NVL(ENDDATE, SYSDATE) > SYSDATE - 365)
     AND ROWNUM
Plan hash value: 591110695

--------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name                    | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
--------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |                         |       |       |   263K(100)|          |       |       |
|*  1 |  COUNT STOPKEY                       |                         |       |       |            |          |       |       |
|*  2 |   FILTER                             |                         |       |       |            |          |       |       |
|*  3 |    FILTER                            |                         |       |       |            |          |       |       |
|   4 |     PARTITION RANGE SINGLE           |                         |    90 |  3060 |   263K  (2)| 00:52:44 |     4 |     4 |
|*  5 |      TABLE ACCESS FULL               | SUBS_SERVICE            |    90 |  3060 |   263K  (2)| 00:52:44 |     4 |     4 |
|   6 |    PARTITION RANGE SINGLE            |                         |     1 |    22 |     6   (0)| 00:00:01 |   KEY |   KEY |
|*  7 |     TABLE ACCESS BY LOCAL INDEX ROWID| SUBS_SERVICE            |     1 |    22 |     6   (0)| 00:00:01 |   KEY |   KEY |
|*  8 |      INDEX RANGE SCAN                | IDX_SUBS_SERVICE_SUBSID |     1 |       |     4   (0)| 00:00:01 |   KEY |   KEY |
--------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(ROWNUM    2 - filter( IS NULL)
   3 - filter(SYSDATE@!-395    5 - filter((INTERNAL_FUNCTION("SERVICEID") AND "STATUS"8 AND "STATUS"9 AND "ENDDATE"               "ENDDATE">=SYSDATE@!-395 AND "REGION"=23))
   7 - filter(("B"."REGION"=:B1 AND NVL("ENDDATE",SYSDATE@!)>SYSDATE@!-365))
   8 - access("B"."SUBSID"=:B1)
       filter(("B"."SERVICEID"=:SERVICEID1 OR "B"."SERVICEID"=:SERVICEID2 OR "B"."SERVICEID"=:SERVICEID3))

这里很明显有个bad的执行计划table access full SUBS_SERVICE的全表扫描,通过谓词条件基本可以得知正式因为这个bad的执行计划导致,而优化这个sql其实很简单就是建立合适的索引。

那么接下来如何建立索引了,我们看执行计划ID:5对应的谓词条件是enddate和serviceid的两个列的条件,而serviceid的不同值较少,enddate的不同值相对较多。

Table                                  Number                        Empty    Chain Average Global         Sample Date
Name                                  of Rows          Blocks       Blocks    Count Row Len Stats            Size MM-DD-YYYY
------------------------------ -------------- --------------- ------------ -------- ------- ------ -------------- ----------
SUBS_SERVICE                      322,621,100       56,409,85            0        0     109 YES        16,131,055 09-28-2014

Column                             Distinct              Number       Number         Sample Date
Name                                 Values     Density Buckets        Nulls           Size MM-DD-YYYY
------------------------------ ------------ ----------- ------- ------------ -------------- ----------
SUBSID                           18,668,054   .00000005       1            0     16,131,055 09-28-2014
REGION                                    4   .25000000       1            0     16,131,055 09-28-2014
SERVICEID                               402   .00248756       1            0     16,131,055 09-28-2014
ENDDATE                           1,628,520   .00000061       1  258,160,160      3,223,047 09-28-2014
STATUS                                    7   .14285714       1            0     16,131,055 09-28-2014
...

这种情况下,我们一般可能都是选择的enddate作为前导列,serviceid作为后导列的组合索引,也是为了能够有效的利用enddate作为前导列去驱动别的sql语句来利用这个索引。

挖掘shared pool和sql历史的执行信息:

SQL> select sql_id
  2    from gv$sql_plan
  3   where options = 'FULL'
  4     and object_owner = 'TBCS'
  5     and object_name like 'SUBS_SERVICE'
  6     and instr(filter_predicates, 'ENDDATE') > 0
  7     and instr(filter_predicates, 'SERVICEID')
no rows selected

SQL> select sql_id
  2    from dba_hist_sql_plan
  3   where object_owner = 'TBCS'
  4     and object_name like 'SUBS_SERVICE'
  5     and instr(filter_predicates, 'ENDDATE') > 0
  6     and instr(filter_predicates, 'SERVICEID')

挖掘shared pool中发觉没有单独出现enddate的sql语句,那么是没有别的sql语句能够利用enddate为前缀的索引来索引扫描的。

虽然这里enddate的前缀索引可能没有办法作用于别的sql语句,但是对于这个sql而言,建立索引是必然的,首先建立enddate的前缀的复合索引ind_enddate_serviceid

SQL> create index tbcs.ind_enddate_serviceid on tbcs.subs_service(enddate,serviceid)

Index created.

执行上述sql语句,查看每个步骤产生的逻辑读和资源消耗
SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  f1cmqc5sag5s0, child number 0
-------------------------------------
SELECT /*+gather_plan_statistics*/OID, SUBSID
    FROM tbcs.SUBS_SERVICE A
    WHERE SERVICEID IN (:SERVICEID1, :SERVICEID2, :SERVICEID3)
       AND ENDDATE        AND ENDDATE >= SYSDATE - 395
       AND REGION = 23
       AND STATUS 8
       AND STATUS 9
       AND NOT EXISTS (SELECT 1
              FROM tbcs.SUBS_SERVICE B
              WHERE B.REGION = A.REGION
                      AND B.SUBSID = A.SUBSID
                      AND B.SERVICEID IN (:SERVICEID1, :SERVICEID2, :SERVICEID3)
                      AND NVL(ENDDATE, SYSDATE) > SYSDATE - 365)
      AND ROWNUM
Plan hash value: 2714263820

------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name                    | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |
------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                         |      1 |        |    200 |00:00:16.94 |    2619 |   1797 |
|*  1 |  COUNT STOPKEY                        |                         |      1 |        |    200 |00:00:16.94 |    2619 |   1797 |
|*  2 |   FILTER                              |                         |      1 |        |    200 |00:00:16.94 |    2619 |   1797 |
|*  3 |    FILTER                             |                         |      1 |        |    261 |00:00:44.31 |    1237 |   1218 |
|*  4 |     TABLE ACCESS BY GLOBAL INDEX ROWID| SUBS_SERVICE            |      1 |     90 |    261 |00:00:44.31 |    1237 |   1218 |
|*  5 |      INDEX RANGE SCAN                 | IND_ENDDATE_SERVICEID   |      1 |     20 |   2078 |00:00:02.73 |     873 |    859 |
|   6 |    PARTITION RANGE SINGLE             |                         |    257 |      1 |     58 |00:00:04.86 |    1382 |    579 |
|*  7 |     TABLE ACCESS BY LOCAL INDEX ROWID | SUBS_SERVICE            |    257 |      1 |     58 |00:00:04.86 |    1382 |    579 |
|*  8 |      INDEX RANGE SCAN                 | IDX_SUBS_SERVICE_SUBSID |    257 |      1 |    325 |00:00:04.22 |    1057 |    510 |
------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(ROWNUM    2 - filter( IS NULL)
   3 - filter(SYSDATE@!-395    4 - filter(("STATUS"8 AND "STATUS"9 AND "REGION"=23))
   5 - access("ENDDATE">=SYSDATE@!-395 AND "ENDDATE"        filter(("SERVICEID"=:SERVICEID1 OR "SERVICEID"=:SERVICEID2 OR "SERVICEID"=:SERVICEID3))
   7 - filter(("B"."REGION"=:B1 AND NVL("ENDDATE",SYSDATE@!)>SYSDATE@!-365))
   8 - access("B"."SUBSID"=:B1)
       filter(("B"."SERVICEID"=:SERVICEID1 OR "B"."SERVICEID"=:SERVICEID2 OR "B"."SERVICEID"=:SERVICEID3))

sql语句已经走了ind_enddate_serviceid的索引范围扫描,执行计划id:5索引范围扫描消耗的逻辑读为873,而后回表达到了1237的逻辑读

而我们看ID:5 oracle通过(enddate,serviceid)组合索引IND_ENDDATE_SERVICEID只能用access过滤满足enddate的条件,需要filter再次对serviceid的条件进行过滤

这种情况下index range scan只需要扫描满足enddate的谓词条件,会扫描更多的叶块节点,产生更多的逻辑读。

那么既然ind_enddate_serviceid的索引其实在index range scan部分索引的范围扫描只针对了enddate条件的,那么是否我们可以直接建立enddate的单列索引了。

SQL> create index tbcs.ind_enddate on tbcs.subs_service(enddate);

Index created.

SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  c12gvu0qs792j, child number 0
-------------------------------------
 SELECT /*+gather_plan_statistics index(A,ind_enddate)*/OID, SUBSID
    FROM tbcs.SUBS_SERVICE A
    WHERE SERVICEID IN (:SERVICEID1, :SERVICEID2, :SERVICEID3)
       AND ENDDATE        AND ENDDATE >= SYSDATE - 395
       AND REGION = 23
       AND STATUS 8
       AND STATUS 9
       AND NOT EXISTS (SELECT 1
              FROM tbcs.SUBS_SERVICE B
              WHERE B.REGION = A.REGION
                      AND B.SUBSID = A.SUBSID
                      AND B.SERVICEID IN (:SERVICEID1, :SERVICEID2, :SERVICEID3)
                      AND NVL(ENDDATE, SYSDATE) > SYSDATE - 365)
      AND ROWNUM
Plan hash value: 439697064

------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name                    | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |
------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                         |      1 |        |    200 |00:10:41.48 |   37372 |  32157 |
|*  1 |  COUNT STOPKEY                        |                         |      1 |        |    200 |00:10:41.48 |   37372 |  32157 |
|*  2 |   FILTER                              |                         |      1 |        |    200 |00:10:41.48 |   37372 |  32157 |
|*  3 |    FILTER                             |                         |      1 |        |    261 |00:06:07.29 |   35990 |  32095 |
|*  4 |     TABLE ACCESS BY GLOBAL INDEX ROWID| SUBS_SERVICE            |      1 |     90 |    261 |00:06:07.29 |   35990 |  32095 |
|*  5 |      INDEX RANGE SCAN                 | IND_ENDDATE             |      1 |   2810 |    199K|00:00:03.08 |     660 |    646 |
|   6 |    PARTITION RANGE SINGLE             |                         |    257 |      1 |     58 |00:00:00.11 |    1382 |     62 |
|*  7 |     TABLE ACCESS BY LOCAL INDEX ROWID | SUBS_SERVICE            |    257 |      1 |     58 |00:00:00.11 |    1382 |     62 |
|*  8 |      INDEX RANGE SCAN                 | IDX_SUBS_SERVICE_SUBSID |    257 |      1 |    325 |00:00:00.09 |    1057 |     50 |
------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(ROWNUM    2 - filter( IS NULL)
   3 - filter(SYSDATE@!-395    4 - filter((INTERNAL_FUNCTION("SERVICEID") AND "STATUS"8 AND "STATUS"9 AND "REGION"=23))
   5 - access("ENDDATE">=SYSDATE@!-395 AND "ENDDATE"    7 - filter(("B"."REGION"=:B1 AND NVL("ENDDATE",SYSDATE@!)>SYSDATE@!-365))
   8 - access("B"."SUBSID"=:B1)
       filter(("B"."SERVICEID"=:SERVICEID1 OR "B"."SERVICEID"=:SERVICEID2 OR "B"."SERVICEID"=:SERVICEID3))

由于ind_enddate是单列索引,每个叶块存储的键值会多些,那么index range scan部分消耗应该会更小,其实果然也是如我们推断的,但是我们发觉在通过ind_enddate回表时逻辑读增加到了35990

这个是由于虽然扫描的索引叶块更少了,但是扫描完后不能做任何进一步的过滤,导致需要回表的rowid非常多,导致回表成本增加,而在回表后再进行serviceid谓词条件的过滤。

那么除了上述的两种索引的创建方式,是否还有一种更优秀的:

如果我们创建serviceid作为前导列,enddate作为后导列的索引ind_serviceid_enddate

SQL> create index tbcs.ind_serviceid_enddateon tbcs.subs_service(serviceid,enddate);

SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  48bfmd32ag3nk, child number 0
-------------------------------------
SELECT /*+gather_plan_statistics*/OID, SUBSID
FROM tbcs.SUBS_SERVICE A
WHERE SERVICEID IN (:SERVICEID1, :SERVICEID2, :SERVICEID3)
     AND ENDDATE      AND ENDDATE >= SYSDATE - 395
     AND REGION = 23
     AND STATUS 8
     AND STATUS 9
     AND NOT EXISTS (SELECT 1
          FROM tbcs.SUBS_SERVICE B
          WHERE B.REGION = A.REGION
               AND B.SUBSID = A.SUBSID
               AND B.SERVICEID IN (:SERVICEID1, :SERVICEID2, :SERVICEID3)
               AND NVL(ENDDATE, SYSDATE) > SYSDATE - 365)
     AND ROWNUM    
Plan hash value: 771671576

----------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                              | Name                    | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
----------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                       |                         |      1 |        |    200 |00:00:00.01 |    1745 |
|*  1 |  COUNT STOPKEY                         |                         |      1 |        |    200 |00:00:00.01 |    1745 |
|*  2 |   FILTER                               |                         |      1 |        |    200 |00:00:00.01 |    1745 |
|*  3 |    FILTER                              |                         |      1 |        |    256 |00:00:00.01 |     373 |
|   4 |     INLIST ITERATOR                    |                         |      1 |        |    256 |00:00:00.01 |     373 |
|*  5 |      TABLE ACCESS BY GLOBAL INDEX ROWID| SUBS_SERVICE            |      1 |     90 |    256 |00:00:00.01 |     373 |
|*  6 |       INDEX RANGE SCAN                 | IND_SERVICEID_ENDDATE   |      1 |     20 |   3186 |00:00:00.01 |      33 |
|   7 |    PARTITION RANGE SINGLE              |                         |    256 |      1 |     56 |00:00:00.01 |    1372 |
|*  8 |     TABLE ACCESS BY LOCAL INDEX ROWID  | SUBS_SERVICE            |    256 |      1 |     56 |00:00:00.01 |    1372 |
|*  9 |      INDEX RANGE SCAN                  | IDX_SUBS_SERVICE_SUBSID |    256 |      1 |    328 |00:00:00.01 |    1044 |
----------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(ROWNUM    2 - filter( IS NULL)
   3 - filter(SYSDATE@!-395    5 - filter(("STATUS"8 AND "STATUS"9 AND "REGION"=23))
   6 - access((("SERVICEID"=:SERVICEID1 OR "SERVICEID"=:SERVICEID2 OR "SERVICEID"=:SERVICEID3)) AND
              "ENDDATE">=SYSDATE@!-395 AND "ENDDATE"    8 - filter(("B"."REGION"=:B1 AND NVL("ENDDATE",SYSDATE@!)>SYSDATE@!-365))
   9 - access("B"."SUBSID"=:B1)
       filter(("B"."SERVICEID"=:SERVICEID1 OR "B"."SERVICEID"=:SERVICEID2 OR "B"."SERVICEID"=:SERVICEID3))

以serviceid前导列索引前提下,执行计划ID:6 oracle通过(serviceid,enddate)组合索引IND_SERVICEID_ENDDATE可以全部用access的方式完成index range scan,

此时index range scan只会扫描同时满足serviceid和enddate的谓词条件的索引叶块,相对索引ind_enddate_serviceid而言,serviceid作为前导列的索引在index range scan扫描更少索引叶块,相应的逻辑读也会更低。

而如果我们细心观察发现索引ind_enddate_serviceid和ind_serviceid_enddate主要区别是在是否在index range scan阶段能够直接access方式读取数据,而在回表阶段其实消耗的逻辑读大体相同。

ind_enddate_serviceid回表的逻辑读=1237-873=364

ind_serviceid_enddate回表的逻辑读=373-33=340

区别主要在于index range scan部分的区别,两个复合索引扫描的叶块是完全不同的,索引能够全部走access的索引必然成本要低很多,而先走access然后走filter的索引,虽然回表成本不变,但是index range scan部分会扫描很多不满足的条件的leaf block,导致index range scan部分逻辑读增加。

这里我们再看一个sql语句,如果是两个范围的索引如何去创建索引:

SQL> SELECT OID, SUBSID
  2  FROM tbcs.SUBS_SERVICE A
  3  WHERE SERVICEID between :serviceid1 and :serviceid3
  4     AND ENDDATE   5     AND ENDDATE >= SYSDATE - 395
  6     AND REGION = 23
  7     AND STATUS 8
  8     AND STATUS 9
  9     AND NOT EXISTS (SELECT 1
 10             FROM tbcs.SUBS_SERVICE B
 11             WHERE B.REGION = A.REGION
 12                     AND B.SUBSID = A.SUBSID
 13                     AND B.SERVICEID IN (:SERVICEID1, :SERVICEID2, :SERVICEID3)
 14                     AND NVL(ENDDATE, SYSDATE) > SYSDATE - 365)
 15     AND ROWNUM
200 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 928699648

---------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name                    | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
---------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                         |    30 |  1020 |  4813   (1)| 00:00:58 |       |       |
|*  1 |  COUNT STOPKEY                        |                         |       |       |            |          |       |       |
|*  2 |   FILTER                              |                         |       |       |            |          |       |       |
|*  3 |    FILTER                             |                         |       |       |            |          |       |       |
|*  4 |     TABLE ACCESS BY GLOBAL INDEX ROWID| SUBS_SERVICE            |    30 |  1020 |  4807   (1)| 00:00:58 |     4 |     4 |
|*  5 |      INDEX RANGE SCAN                 | IND_SERVICEID_ENDDATE   |    12 |       |  4776   (1)| 00:00:58 |       |       |
|   6 |    PARTITION RANGE SINGLE             |                         |     1 |    22 |     6   (0)| 00:00:01 |   KEY |   KEY |
|*  7 |     TABLE ACCESS BY LOCAL INDEX ROWID | SUBS_SERVICE            |     1 |    22 |     6   (0)| 00:00:01 |   KEY |   KEY |
|*  8 |      INDEX RANGE SCAN                 | IDX_SUBS_SERVICE_SUBSID |     1 |       |     4   (0)| 00:00:01 |   KEY |   KEY |
---------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(ROWNUM    2 - filter( NOT EXISTS (SELECT 0 FROM "TBCS"."SUBS_SERVICE" "B" WHERE "B"."SUBSID"=:B1 AND "B"."REGION"=:B2 AND
              NVL("ENDDATE",SYSDATE@!)>SYSDATE@!-365 AND ("B"."SERVICEID"=:SERVICEID1 OR "B"."SERVICEID"=:SERVICEID2 OR
              "B"."SERVICEID"=:SERVICEID3)))
   3 - filter(SYSDATE@!-395=:SERVICEID1)
   4 - filter("STATUS"8 AND "STATUS"9 AND "REGION"=23)
   5 - access("SERVICEID">=:SERVICEID1 AND "ENDDATE">=SYSDATE@!-395 AND "SERVICEID"               "ENDDATE"        filter("ENDDATE"=SYSDATE@!-395)
   7 - filter("B"."REGION"=:B1 AND NVL("ENDDATE",SYSDATE@!)>SYSDATE@!-365)
   8 - access("B"."SUBSID"=:B1)
       filter("B"."SERVICEID"=:SERVICEID1 OR "B"."SERVICEID"=:SERVICEID2 OR "B"."SERVICEID"=:SERVICEID3)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
       1732  consistent gets
          2  physical reads
          0  redo size
       7107  bytes sent via SQL*Net to client
        663  bytes received via SQL*Net from client
         15  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
        200  rows processed

这里看见如果是两个范围的谓词,在执行计划ID:5中对应的谓词信息中显示同时有access和filter,而比较奇怪的是access阶段其实已经有了enddate的过滤条件,但是filter中又包含了同样的access的过滤条件,那么这个index range scan究竟是怎么完成扫描的。

这里oracle是先找到了”SERVICEID”>=:SERVICEID1 AND “ENDDATE”>=SYSDATE@!-395索引入口,然后通过索引的双向指针左右滑动来查找数据,但是由于range scan的过程中,没办法保证每个leaf block都是满足enddate的条件的,事实也是确实如此,指针滑动过程中肯定有可能出现不满足enddate的条件的数据,比如这里出现了(serviceid2,enddate-10000)的键值,而且serviceid2是大于serviceid1的,这个键值也会出现在(serviceid1,enddate-365)的右边,所以在access完成后还需要filter满足enddate的leaf block。

创建复合索引时:如果单纯为了调整某类sql语句,不考虑别的sql是否能够最大程度的使用该索引,一般将等值条件的列作为索引的前导列,这样cbo能够尽可能的在index range scan部分只扫描满足条件的leaf block。

可以参考下兔子的一篇大作: http://blog.chinaunix.net/uid-7655508-id-3639188.html

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

SQL IF 문을 사용하는 방법 SQL IF 문을 사용하는 방법 Apr 09, 2025 pm 06:12 PM

SQL IF 명령문은 구문을 다음과 같이 조건부로 실행하는 데 사용됩니다. if (조건) 그런 다음 {state} else {state} end if;. 조건은 유효한 SQL 표현식 일 수 있으며 조건이 참이면 당시 조항을 실행하십시오. 조건이 false 인 경우 else 절을 ​​실행하십시오. 명세서를 중첩 할 수있는 경우 더 복잡한 조건부 점검이 가능합니다.

도메인의 Vue Axios로 인한 '네트워크 오류'를 해결하는 방법 도메인의 Vue Axios로 인한 '네트워크 오류'를 해결하는 방법 Apr 07, 2025 pm 10:27 PM

Vue Axios의 크로스 도메인 문제를 해결하는 방법 : Cors 플러그인을 사용하여 Websocket을 사용하여 JSONP를 사용하여 Axios 프록시를 사용하여 서버 측의 CORS 헤더 구성

Apache의 Zend를 구성하는 방법 Apache의 Zend를 구성하는 방법 Apr 13, 2025 pm 12:57 PM

Apache에서 Zend를 구성하는 방법은 무엇입니까? Apache 웹 서버에서 Zend 프레임 워크를 구성하는 단계는 다음과 같습니다. Zend 프레임 워크를 설치하고 웹 서버 디렉토리로 추출하십시오. .htaccess 파일을 만듭니다. Zend 응용 프로그램 디렉토리를 작성하고 Index.php 파일을 추가하십시오. Zend 응용 프로그램 (application.ini)을 구성하십시오. Apache 웹 서버를 다시 시작하십시오.

C#에서 멀티 스레딩의 이점은 무엇입니까? C#에서 멀티 스레딩의 이점은 무엇입니까? Apr 03, 2025 pm 02:51 PM

멀티 스레딩의 장점은 특히 많은 양의 데이터를 처리하거나 시간이 많이 걸리는 작업을 수행하기 위해 성능 및 리소스 활용도를 향상시킬 수 있다는 것입니다. 이를 통해 여러 작업을 동시에 수행하여 효율성을 향상시킬 수 있습니다. 그러나 너무 많은 스레드가 성능 저하로 이어질 수 있으므로 CPU 코어 수와 작업 특성에 따라 스레드 수를 신중하게 선택해야합니다. 또한 다중 스레드 프로그래밍에는 교착 상태 및 레이스 조건과 같은 과제가 포함되며 동기화 메커니즘을 사용하여 해결해야하며 동시 프로그래밍에 대한 확실한 지식, 장단점을 측정하고주의해서 사용해야합니다.

MySQL에 루트로 로그인 할 수 없습니다 MySQL에 루트로 로그인 할 수 없습니다 Apr 08, 2025 pm 04:54 PM

Root로 MySQL에 로그인 할 수없는 주된 이유는 권한 문제, 구성 파일 오류, 암호 일관성이 없음, 소켓 파일 문제 또는 방화벽 차단입니다. 솔루션에는 다음이 포함됩니다. 구성 파일의 BAND-ADDRESS 매개 변수가 올바르게 구성되어 있는지 확인하십시오. 루트 사용자 권한이 수정 또는 삭제되어 재설정되었는지 확인하십시오. 케이스 및 특수 문자를 포함하여 비밀번호가 정확한지 확인하십시오. 소켓 파일 권한 설정 및 경로를 확인하십시오. 방화벽이 MySQL 서버에 연결되는지 확인하십시오.

데비안에서 nginx ssl 성능을 모니터링하는 방법 데비안에서 nginx ssl 성능을 모니터링하는 방법 Apr 12, 2025 pm 10:18 PM

이 기사에서는 데비안 시스템에서 NGINX 서버의 SSL 성능을 효과적으로 모니터링하는 방법에 대해 설명합니다. NginxOxporter를 사용하여 Nginx 상태 데이터를 프로 메테우스로 내보낸 다음 Grafana를 통해 시각적으로 표시합니다. 1 단계 : nginx 구성 먼저 Nginx 구성 파일에서 stub_status 모듈을 활성화하여 nginx의 상태 정보를 얻어야합니다. nginx 구성 파일에 다음 스 니펫을 추가하십시오 (일반적으로 /etc/nginx/nginx.conf에 있거나 포함 파일에 위치) : location/nginx_status {stub_status

phpmyadmin 취약성 요약 phpmyadmin 취약성 요약 Apr 10, 2025 pm 10:24 PM

Phpmyadmin 보안 방어 전략의 핵심은 다음과 같습니다. 1. Phpmyadmin의 최신 버전을 사용하고 정기적으로 PHP 및 MySQL을 업데이트합니다. 2. 액세스 권한을 엄격하게 제어하고, .htaccess 또는 웹 서버 액세스 제어 사용; 3. 강력한 비밀번호와 2 단계 인증을 활성화합니다. 4. 데이터베이스를 정기적으로 백업하십시오. 5. 민감한 정보를 노출하지 않도록 구성 파일을주의 깊게 확인하십시오. 6. WAF (Web Application Firewall) 사용; 7. 보안 감사를 수행하십시오. 이러한 조치는 부적절한 구성, 이전 버전 또는 환경 보안 위험으로 인해 PhpmyAdmin으로 인한 보안 위험을 효과적으로 줄이고 데이터베이스의 보안을 보장 할 수 있습니다.

DICR/YII2-Google을 사용하여 YII2에서 Google API를 통합합니다 DICR/YII2-Google을 사용하여 YII2에서 Google API를 통합합니다 Apr 18, 2025 am 11:54 AM

vprocesserazrabotkiveb-enclosed, мнепришлостольносться악 · 뇨 зейейерациигоглапи혁 맥발 추배. LeavallysumballancefriAblancefaumdoMatification, čtookazalovnetakprosto, Kakaožidal.posenesko

See all articles